I mean the example is not a useful example because it doesn't show the problem "my" representation solves, which is to make closures independent of their enclosing activations if they outlive their dynamic extent.
Yes I'm starting to finish the chapter explanation on explicit return and now I will go in "opening the trunk section" and study for real your implementation because I really want to fully understand it. Stef
(define (%apply proc largs) (cond ((%primitive? proc) (%apply-internal proc largs)) ((%closure? proc) (%apply-closure proc largs)) (else (error "Bad ! Un-apply-able object !" proc))))
(define (%apply-closure proc largs) ;; apply a closure: evaluate proc body in ;; extended the closure environment with ;; proc arguments and largs (%eval (%closure-body proc) (%extend-env (%closure-args proc) largs (%closure-env proc))))
(define (%eval-lambda expr env) ;; lambda in Scheme captures the environment at compile time ;; expr = ((x) (+ x 2)) (%make-closure (car expr) (cadr expr) env))
You need to consider how to implement this example:
Object subclass: #AbstractSuperclass
AbstractSuperclass>>computeV | v | v := 0. self maybeCapture: [v := v + 1. v]. ^self maybeBlock: v
AbstractSuperclass subclass: #CaptureBlock instanceVariableNames: 'block'
CaptureBlock>>maybeCapture: aBlock block := aBlock
CaptureBlock>>maybeBlock: value ^block
AbstractSubclass subclass: #DontCaptureBlock
DontCaptureBlock>>maybeCapture: aBlock
DontCaptureBlock>>maybeBlock: value ^value
Then | thingOne thingTwo | thingOne := CaptureBlock computeV. thingTwo := DontCaptureBlock computeV. (1 to: 10) collect: [:ignore| { thingOne value. thingTwo value }]
should answer #((1 0) (2 0) (3 0) ... (10 0))
if 0 value returns 0? yes. (it confused me for a while).
right? So where does the l-value for v in computeV live? Iy must be an l-value since it is assigned to in the block in computeV. It must outlive the activation of computeV since CaptureBlock>maybeCapture: captures the block and CaptureBlock>>maybeBlock: answers it and the doit evaluates it. If it lives on the stack of the activation of computeV then there is no problem in a Context VM, but in a VM that maps activations to stack frames something special (and slow) has to happen when returning from computeV. However, if the l-value lives in a separate Array (as it does in my VisualWorks and Squeak closure implementations, and as happens in some Lisp implementations), nothing special has to happen. The block refers to the Array, *not* to the activation of computeV.
Make sense now?
Yes you allocate on the heap closure binding to be orthogonal to activation context.
I will reread your blog now.
Stef
-- best, Eliot