Ever wanted to use Once
(once-per-session evaluation) for efficiency within a computationally expensive function but you still wanted to be able to override it easily sometimes within a session? This is how! CreateUUID[]
to the rescue:
In this demo a Pause is used so you can tell whether it's caching:
fCache[a_, $uuid:(_String|None):None] :=
Once[($uuid; Pause[a]; a^2)];
Create a uuid and pass it first time (or use the default None) :
i: $uuid1 = CreateUUID[]
o: f8deb36b-b2a5-4538-a782-9631425696da
The first time you call fCache
it will run, which you can tell here in this demo by the Pause
:
i: fCache[2,$uuid1]
(* ... wait 2 seconds ... *)
o: 4
[BTW: You can also do a Print[$uuid]
to see it happening better, but not in production code of course.]
The next time you call fCache
it will just return the pre-computed result under control of Once
:
i: fCache[2,$uuid1]
(* "instantaneous", well almost *)
o: 4
In fact you don't need to pass in that $uuid
every time, since Once
looks after it for you:
i: fCache[2]
(* "instantaneous" again, well almost *)
o: 4
To force it to re-compute again, just feed it a fresh UUID using CreateUUID[]
:
i: fCache[2,CreateUUID[]]
(* ... wait 2 seconds again ... *)
o: 4
[© Copyright Brad Bird and PIXAR or someone, reproduced solely for educational purposes.]
Note that in the example as shown, the '$uuid' isn't doing anything other than forcing the Once to re-trigger. It will also work if you have another delegate function with that uses the '$uuid' somehow (possible also with UUID-driven Once-caching):
fOuterCache[i_Integer, $uuid:(_String|None):None] :=
Once[
fUuidToInteger[$uuid] + i
];
The Webel libraries for Mathematica have a short alias uu[]
for CreateUUID[]
, because this UUID-driven Once-caching is used often in combination with the Webel ADT recipe.
So why would one want to do this UUID-driven Once-caching?
A few cases:
- You are reloading changed/edited function code during development, but you want it to otherwise cache most of the time (not just "once"). Very handy.
- Your function depends on something randomly generated internally, as used in the Wolfram online help example for
Once
usingRandom
, which example is of course not pure stateless functional, but it's a very nice demo. - You are very, very naughty, and your function is deliberately not pure stateless functional, so the result could change because of other happenings elsewhere each time it is invoked, and that doesn't worry you, you can live perfectly well with that and still look yourself in the mirror, even if it's not "the Mathematica way".
- You are proudly and knowingly and with full awareness using the stateful capabilities of the user-contributed MTools package for (some) OO in Mathematica, but you want control over when to "hit" the state (also useful during development). Because you know that state is not "evil" per se if you know how to use it well. (And besides, use of some aspects of OO does not automatically imply use of its stateful capabilities, but that's another story for another time, and not really relevant here.)
Once[expr, loc]
This UUID-driven
Once
caching trick is used in the Webel recipe for Abstract Data Type (ADT) pseudo-classes with inheritance: