[Cuis-dev] memoizing a method
Luciano Notarfrancesco
luchiano at gmail.com
Thu Dec 5 22:39:26 PST 2024
It’s an interesting idea, but this implementation could cause problems. For
example, the cache only grows, and over time you run out of memory. And the
symbol you create should uniquely identify with the message (receiver,
selector, arguments), maybe you should use the message itself as key
instead? But even considering those things, I’m not sure this is a
practical idea that I’d use in my code.
Have you used a Smalltalk with support for instance-specific methods? I
have some objects that are immutable in some sense (equality is invariant
over the instances lifetime, but they can change state as long as it
doesn’t break that invariant, for example to cache computations, or to do
lazy initialization and let some data be computed only when needed). These
objects often implement some unary messages that are “pure functions”, i.e.
they will always compute the same value for a given instance, so they could
be cached. I normally cache them in a properties dictionary that each
instance has, sometimes in an instance variable, but if we had
instance-specific methods I could just use that. For example, say you want
to do this for the average of #(1 2 3), then you implement the method
>>#average so that at the end, before returning the computed value, adds a
new instance method #average to the receiver that stores that value as a
literal and just returns that value, i.e. a method that decompiled would
look like this:
average
^ 2
The next time you send #average to #(1 2 3) it it will just return the
stored value, only for the instance #(1 2 3).
I don’t think there’s any plan to support this in Cuis or the OpenSmalltalk
VM, tho.
Cheers,
Luciano
On Fri, Dec 6, 2024 at 04:24 Mark Volkmann via Cuis-dev <
cuis-dev at lists.cuis.st> wrote:
> Certainly it's not common to want to memoize a method, but I was wondering
> if it would be easy to do. I came up with the following that works well.
> I'd be interested in hearing whether there is a better approach and whether
> something like this is already in the base image and I just haven't found
> it yet.
>
> I added the Object instance method memoize: which takes a block.
> This caches previously computed values in an IdentityDictionary
> that is saved in Smalltalk which is also an IdentityDictionary.
>
> memoize: aBlock
> | cache cacheKey sender valueKey |
>
> sender := thisContext sender.
>
> "Smalltalk is a SystemDictionary which is an IdentityDictionary.
> That is why cacheKey must be a Symbol."
> cacheKey := ('cache-', sender name) asSymbol.
>
> cache := Smalltalk at: cacheKey ifAbsentPut: [ IdentityDictionary new
> ].
> valueKey := thisContext name, sender arguments asString :: asSymbol.
>
> ^ cache at: valueKey ifAbsentPut: [ aBlock value ].
>
> Using the memoize: method is demonstrated in the class method average:
> below
> (added to any class) which takes an array of numbers.
>
> average: numberArray
> ^ self memoize: [
> | sum |
> 'computing average' print.
> sum := numberArray fold: [:acc :n | acc + n].
> sum / numberArray size.
> ].
>
>
> --
> R. Mark Volkmann
> Object Computing, Inc.
> --
> Cuis-dev mailing list
> Cuis-dev at lists.cuis.st
> https://lists.cuis.st/mailman/listinfo/cuis-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cuis.st/mailman/archives/cuis-dev/attachments/20241206/464b522a/attachment.htm>
More information about the Cuis-dev
mailing list