On Mon, Apr 30, 2012 at 4:01 AM, Stéphane Ducasse <[email protected]
> wrote:

> >
> >
> > foo
> >
> >        |b|
> >        b := 3.
> >        ^ [ |a | a :=2.  a]
> >
> > In my stupid lisp implementation an environment is represented by
> bindings and closure points to their own environment
> > so
> >        [ |a | a :=2.  a]
> >        points to
> >                (b.3) (toplevel)  (and not top-level)
> >
> > and for closure execution we just added temporaly a binding for a to the
> closure environment.
> >                eval a:=2. a in (a) (b.3) (toplevel)
> >
> > This is the wrong example.
>
> I understand your example below and the fact that closure environment is
> allocated on the heap via an array to be independent of the activation
> context but I do not get why consing the local environment to be one
> current one is wrong.
>

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.


> (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

Reply via email to