[Cuis-dev] Animator class>>composedActionExample2 crashes the VM

Szabolcs Komáromi cuis at mnqpr.com
Mon Oct 2 13:03:17 PDT 2023


Thanks for the explanation! I needed a few days to grok it. Now I can reproduce the bug in a very simple class and also prevent it. I have a copy of Structure & Interpretation of Programming Languages and it is on my reading list, but I was a little bit lazy to read it. :)

Thanks again!
Regards,
Szabolcs

On Thu, Sep 28, 2023, at 23:57, ken.dickey at whidbey.com wrote:
> On 2023-09-28 13:06, Szabolcs Komáromi via Cuis-dev wrote:
> 
> > I need little bit more context to fully grasp the problem.
> 
> It is subtle.  The crux is to know which closure captured values are 
> shared and which are unique.
> 
> The original code had an #action method that returned a closure which 
> captured a reference to the `action` instance variable. So each 
> invocation of the closure got a value from the `action` ivar.
> 
> In the #composedActionExample2 method, there is code to assign a new 
> composite closure which contains code to invoke both the new and the 
> original action-closures.
> 
> So when the composed action-closure is invoked, it does the new action 
> and then invokes the "original" action-closure which gets the value from 
> the action-ivar which _now_ contains the new, composite closure.  This 
> closure invokes the new action and then invokes the second, "original" 
> closure which goes back to the ivar for its value, gets the composite 
> closure which... recurses a lot until it runs out of stack space.
> 
> By introducing a local variable into closure result of the #action 
> method, the composite closure then is invoked with the new action, then 
> the original action.  The "original" action now returns the closed over 
> local (cached) closure and does NOT go to the ivar named #action, so the 
> expected result it achieved -- each action-closure is invoked only once. 
>   Whew! :)
> 
> > Is there any recommended book/paper about BlockClosures in the Squeak 
> > family of Smalltalk dialects? Are the Blue Book or the Inside Smalltalk 
> > still relevant in this question?
> 
> My recollection is that early Smalltalks had Block Contexts, NOT 
> Closures, so I expect the Blue Book would be unhelpful in this case.  I 
> would expect Scheme would be more helpful (e.g. Structure & 
> Interpretation of Programming Languages) if Wikipedia is too opaque.
> 
> The crux is when closure captured values are shared and when they are 
> unique.
> 
> A couple of interesting use-cases:
> 
> In Morphic-Games-Solitare, $CardTableMorph>>slide:to:nSteps:delay:next: 
> moves a card from one location to another.  It uses closures to capture 
> position information.
> 
> vvv===vvv===vvv===vvv
> slide: aMorph
> to: endPoint
> nSteps: numSteps
> delay: milliSecondsDelay
> next: nextAction
> 
>    "Slide from current to new position -- in owner's coordinates"
>    "Nota Bene: Asynchronous.  When complete,  nextAction value"
> 
>    | startPoint delta stepCount |
>    startPoint 
 aMorph morphPosition.
>    delta 
 (endPoint - startPoint) / numSteps.
>    stepCount := 0.
>    aMorph when: #morphicStep
>   evaluate: [ :ignoredArgument |
> stepCount := stepCount + 1.
> (stepCount < numSteps)
> ifTrue: [
> aMorph morphPosition:
>      (startPoint + (stepCount  * delta)) rounded;
> redrawNeeded
> ]
> ifFalse: [ "done"
> aMorph stopStepping.
> aMorph morphPosition: endPoint.
> aMorph removeActionsForEvent: #morphicStep.
> nextAction value
> ]
> ].
>    aMorph startSteppingStepTime: milliSecondsDelay
> ^^^===^^^===^^^===^^^
> 
> CardTableMorph>>addingCardOrCards:toContainer: uses closures to 
> capture/remember  undo actions.
> 
> vvv===vvv===vvv===vvv
> addingCardOrCards: cardMorph toContainer: cardContainer
> 
>    "Container is about to add a Card or Cards.  Remember undo action."
> 
>    | startContainer |
>    startContainer := cardMorph valueOfProperty: #moveStart.
>    cardMorph removeProperty:  #moveStart.
>    ((self inUndo) or: [startContainer = cardContainer ])
>      ifFalse: [
> self pushUndoObject:
> [ :table :nextAction |
> table animateMoveFrom: cardContainer
> to: startContainer
> moving: cardMorph
> next: nextAction ]
>      ]
> ^^^===^^^===^^^===^^^
> 
> So it is worthwhile to learn about closures (IMHO).
> 
> HTH,
> -KenD
> 
> 
> 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cuis.st/mailman/archives/cuis-dev/attachments/20231002/f0e6f729/attachment.htm>


More information about the Cuis-dev mailing list