[Cuis-dev] Gatekeeper example from "Discovering Smalltalk"

Juan Vuletich juan at cuis.st
Sun Jan 26 13:34:51 PST 2025


Hi Mark,

Interesting exercise!

Doing `self become: ` is dangerous and tricky. The very method doing 
that will continue execution, but now the receiver is of a different 
class! This would crash the system if that methods tries to access 
instance variables that are not there. The control in #become: that 
bothers you is trying to protect you from that risk.

I suggest slightly different code, to avoid doing `self become:`: move 
the sends to #become. to the class side. So:

class side
on: anObject
     | proxy |
     proxy := self new on: anObject.
     anObject become: proxy.
     ^proxy

instance side
on: anObject
     history := OrderedCollection new.
     object := anObject shallowCopy.
"    anObject become: self"

and class side
restoreAndProvideHistory: aProxy
     | result |
     result := aProxy history.
     aProxy become: aProxy object.
     ^result

Also add the two needed getters #history and #object. Now the workspace 
example does:

history := HistoryProxy restoreAndProvideHistory: date.

This doesn't need any modification to #become:, is more robust and 
future proof, and better style.

Cheers,

On 1/26/2025 4:56 PM, Mark Volkmann via Cuis-dev wrote:
> I recently read the book "Discovering Smalltalk". I know it's quite 
> dated and it's based on Smalltalk/V instead of Smalltalk-80, but I 
> still learned a lot from it.
>
> I implement the Gatekeeper example described on pages 428-430 in Cuis. 
> It demonstrates using the becomes: method to track all messages sent 
> to a given object. I got it working, but I had to make a small 
> modification to the ProtoObject instance method becomes:. I'm 
> wondering if my change would break other uses of this method.
>
> I replaced the line
>
> selfMethod = otherObjectMethod ifFalse: [
>
> with
>
> selfMethod ~= nil and:
> [otherObjectMethod ~= nil] and:
> [selfMethod ~= otherObjectMethod] :: ifTrue: [
>
> Here's my working Gatekeeper code where I renamed that class to 
> HistoryProxy.
>
> Object subclass: #HistoryProxy
>     instanceVariableNames: 'history object'
>     classVariableNames: ''
>     poolDictionaries: ''
>     category: 'Demo'
>
> "class method"
> on: anObject
>     ^ self new on: anObject
>
> "instance method"
> on: anObject
>     history := OrderedCollection new.
>     object := anObject shallowCopy.
>     anObject become: self
>
> "instance method"
> doesNotUnderstand: aMessage
>     "Record the message and reroute it to the object."
>     history add: aMessage.
>     ^ aMessage sendTo: object.
>
> "instance method"
> restoreAndProvideHistory
>     | result |
>     "Extract information before mutating because it won't be available 
> afterwards."
>     result := history.
>     self become: object.
>     ^ result.
>
> Here's an example of using this:
>
> date := Date today.
> HistoryProxy on: date.
> date monthName print.
> date dayOfWeekName print.
> date year print.
> history := date restoreAndProvideHistory.
> history print "an OrderedCollection(monthName dayOfWeekName year)"
>
> -- 
> R. Mark Volkmann
> Object Computing, Inc.


-- 
Juan Vuletich
cuis.st
github.com/jvuletich
researchgate.net/profile/Juan-Vuletich
independent.academia.edu/JuanVuletich
patents.justia.com/inventor/juan-manuel-vuletich
linkedin.com/in/juan-vuletich-75611b3
twitter.com/JuanVuletich

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cuis.st/mailman/archives/cuis-dev/attachments/20250126/f93a2d4a/attachment.htm>


More information about the Cuis-dev mailing list