<div dir="ltr">Thanks for the feedback! I added this class method in <font face="monospace">Object</font> so I can clear the memoized values for a given class and/or method:<div><br></div><div><font face="monospace">clearMemo: aString<br> "Delete all memoized entries from Smalltalk Dictionary whose keys<br> begin with 'memo-' followed by a given string."<br> | prefix |<br> <br> prefix := 'memo-', aString.<br> Smalltalk keys do: [ :key |<br> key isSymbol and: [key asString beginsWith: prefix] :: ifTrue: [ Smalltalk removeKey: key ].<br> ].</font><br></div><div><br></div><div>Of course we can still run out of memory if this is not used at some point and the results of a large number of argument combinations get cached.</div><div><br></div><div>I changed the key prefix from 'cache-' to 'memo-' to more clearly associate them with the <font face="monospace">memoize</font> method.</div><div><br></div><div>The key I'm using does capture the class, selector, and the arguments, but not a specific receiver object. Here's an example key for calls to the class method indentDepth in the class ParseTree: <font face="monospace">#'memo-ParseTree class>>indentDepth:'</font></div><div><br></div><div>Would it be more appropriate to add the <font face="monospace">memoize:</font> and <font face="monospace">clearMemo:</font> methods to the <font face="monospace">Behavior</font> class instead of the <font face="monospace">Object</font> class? Perhaps the answer is that they shouldn't be added to either of those.</div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Fri, Dec 6, 2024 at 12:39 AM Luciano Notarfrancesco <<a href="mailto:luchiano@gmail.com">luchiano@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto">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.</div><div dir="auto"><br></div><div dir="auto">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:</div><div dir="auto"><br></div><div dir="auto">average</div><div dir="auto"> ^ 2</div><div dir="auto"><br></div><div dir="auto">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).</div><div dir="auto"><br></div><div dir="auto">I don’t think there’s any plan to support this in Cuis or the OpenSmalltalk VM, tho.</div><div dir="auto"><br></div><div dir="auto">Cheers,</div><div dir="auto">Luciano</div><div dir="auto"><br></div><div dir="auto"><br></div><div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Dec 6, 2024 at 04:24 Mark Volkmann via Cuis-dev <<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;padding-left:1ex;border-left-color:rgb(204,204,204)"><div dir="ltr"><div>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.</div><div><br></div><div>I added the <font face="monospace" style="font-family:monospace;color:rgb(0,0,0)">Object</font> instance method <font face="monospace" style="font-family:monospace;color:rgb(0,0,0)">memoize:</font> which takes a block.<br>This caches previously computed values in an <font face="monospace" style="font-family:monospace;color:rgb(0,0,0)">IdentityDictionary</font><br>that is saved in <font face="monospace" style="font-family:monospace;color:rgb(0,0,0)">Smalltalk</font> which is also an <font face="monospace" style="font-family:monospace;color:rgb(0,0,0)">IdentityDictionary</font>.<br><br><font face="monospace" style="font-family:monospace;color:rgb(0,0,0)">memoize: aBlock<br> | cache cacheKey sender valueKey |<br><br> sender := thisContext sender.<br><br> "Smalltalk is a SystemDictionary which is an IdentityDictionary.<br> That is why cacheKey must be a Symbol."<br> cacheKey := ('cache-', sender name) asSymbol.<br><br> cache := Smalltalk at: cacheKey ifAbsentPut: [ IdentityDictionary new ].<br> valueKey := thisContext name, sender arguments asString :: asSymbol.<br><br> ^ cache at: valueKey ifAbsentPut: [ aBlock value ].</font><br><br>Using the <font face="monospace" style="font-family:monospace;color:rgb(0,0,0)">memoize:</font> method is demonstrated in the class method <font face="monospace" style="font-family:monospace;color:rgb(0,0,0)">average:</font> below<br>(added to any class) which takes an array of numbers.<br><br></div><div><font face="monospace" style="font-family:monospace;color:rgb(0,0,0)">average: numberArray<br> ^ self memoize: [<br> | sum |<br> 'computing average' print.<br> sum := numberArray fold: [:acc :n | acc + n].<br> sum / numberArray size.<br> ].</font></div></div><div dir="ltr"><div><br></div><div><br></div><span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><div dir="ltr"><div><font face="arial, helvetica, sans-serif" style="font-family:arial,helvetica,sans-serif;color:rgb(0,0,0)">R. Mark Volkmann</font></div><div><span style="font-size:12.8px"><font face="arial, helvetica, sans-serif" style="font-family:arial,helvetica,sans-serif;color:rgb(0,0,0)">Object Computing, Inc.</font></span></div></div></div></div></div></div></div></div></div>
-- <br>
Cuis-dev mailing list<br>
<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a><br>
<a href="https://lists.cuis.st/mailman/listinfo/cuis-dev" rel="noreferrer" target="_blank">https://lists.cuis.st/mailman/listinfo/cuis-dev</a><br>
</blockquote></div></div>
</blockquote></div><div><br clear="all"></div><div><br></div><span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><div dir="ltr"><div><font face="arial, helvetica, sans-serif">R. Mark Volkmann</font></div><div><span style="font-size:12.8px"><font face="arial, helvetica, sans-serif">Object Computing, Inc.</font></span></div></div></div></div></div></div></div></div>