[squeak-dev] Environment declarations vs bindings

Nicolas Cellier nicolas.cellier.aka.nice at gmail.com
Thu Sep 29 16:54:50 UTC 2016


2016-09-29 7:33 GMT+02:00 H. Hirzel <hannes.hirzel at gmail.com>:

> On 9/28/16, Nicolas Cellier <nicolas.cellier.aka.nice at gmail.com> wrote:
> > Since we are at reviewing Environment, here is a small detail that
> bothers
> > me. I already asked some months ago, but silence was the only response,
> so
> > ping.
> >
> > Implementation of Environment is sometimes not obvious:
> > - Environment>>associationAt: uses declarations inst.var..
> > - Environment>>associationOrUndeclaredAt: uses bindings inst.var.
> > How can it be so different, the selector does not speak, does it?
> >
> > OK, there is a flag: #review in one of them, but that does not make code
> > clearer, it's just a smell of over-complexity or ill-naming.
> >
> > Whatever the reason (self explaining code?) Colin does not comment
> > class/methods, that's a fact.
>
> Alternatively a description of the general ideas and the mechanism would
> help.
>
> After all Environments is just a clever combination of a few
> dictionaries  to look up class names? Isn't it?  ;-)
>
> However the fact that people did not move on much finalising the
> implementation of environments  since 2012 shows that it is hard to
> reverse-engineer the intentions from the (incomplete) code.
>
>
> More than that: we only get core functionalities, the intentions are not
written here.
IOW things still are very open.


>
>
>
> > Chris made the effort of commenting Environment but then came this
> > declarations/bindings split, and the comment did rapidly rot.
> > We have here an un-healthy statu quo crying for change.
> >
> > So if we want to at least comment the class with the
> > meaning/role/responsibility of inst vars, here is my understanding:
> >
> > environment bind: #Foo to: 0. just add to the declarations.
> > (You see how names are not obvious: bind does not bind the new binding to
> > bindings).
>
> Environments
>
> bind: aSymbol to: anObject
>         | binding newBinding |
>         newBinding := aSymbol => anObject.
>
This creates either a Global or ClassBinding.
The first one is writeable, the second not.


>
>         binding := declarations associationAt: aSymbol ifAbsent: [nil].
>
A class points to its environment where it is declared.
So we expect this invariant:
    (Foo environment declarationOf: Foo name) value == Foo.
And of course:
    (declarations values select: [:c | c isBehavior]) allSatisfy: [:c | c
environment == self].
For globals I don't know why they are attached to a specific environment.
Just because of mechanism for propagating changes?


>         binding ifNotNil:
>                 [binding class == newBinding class
>                         ifTrue: [binding value: anObject]
>                         ifFalse: [binding becomeForward: newBinding].
>                 ^anObject].
>


Since we different binding classes we cannot just change the value.
Since bindings are shared by bindings inst. var., CompiledMethods and other
environments if we don't use value, we must preserve identity with a
become...

Note: above code protects against Object := Array because ClassBinding
cannot change value.
But not against Object := 1, become protects nothing. It must be handled
somewhere else.


>
>         binding := undeclared associationAt: aSymbol ifAbsent: [nil].
>         binding
>                 ifNil: [binding := newBinding]
>                 ifNotNil:
>                         [undeclared removeKey: aSymbol.
>                         binding class == newBinding class
>                                 ifTrue: [binding value: anObject]
>                                 ifFalse: [binding becomeForward:
> newBinding]].
>
> If we previously had some undeclared reference to such variable name
(normally a Global with nil value), it's time to rebind it.


>         declarations add: binding.
>         self binding: binding addedTo: self.
>
Now propagate the change to every interested observer (those who import
declarations from yourself).


>         ^anObject
>
like at:put: used to do, we still answer the put object.


>
>
> Could you elaborate a bit please?
>
>
See above, by pure reverse engineering ;)

>
>
>
> > If the Environment importSelf, then the ClassBinding/Global also goes to
> > bindings... (thru an observer pattern and the magic of naming policies)
> >
> > The bindings is what is used by the compiler, so what if an environment
> > does not importSelf? It means that the variable it declares are not
> bound,
> > so it is not reachable (kind of invisible class/Global).
> >
> > IOW, the bindings will contain all the imports, including self-imports.
> > importSelf is generally what we want to do, unless weird cases of
> powerless
> > environment for obfuscation or trustless sandboxing reason.
> >
> > Now, associationAt: does not speak for itself. It's too hard to decide if
> > we're speaking of own declarations or bindings... Analyzing the usage is
> > difficult. bindingAt: would be less ambiguous, so IMO we cannot fix
> without
> > semantic shift.
>
> This would need as well elaboration as well a separate thread.
>
>
> > The semantic will be carried by the senders (the Tools), and the tools by
> > usage we want to make of Environment. So we first have to define that:
> what
> > feature do we want to support? With which tool? That probably require yet
> > another thread...
>
> Yes
>

already opened :)


>
> --Hannes
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20160929/0ec5f00d/attachment-0001.htm


More information about the Squeak-dev mailing list