<div dir="ltr"><div><div><div><div><div>Some lessons from this snippet:<br></div></div>- if several undeclared share the same binding, then we should rebind all at once, not just some<br>- the undeclared shall better point weakly to the bindings, letting them being garbaged collected if possible<br></div><div>- what do we expect when we have two unrelated bindings #Foo-&gt;nil in envA undeclared and envB undeclared, then import envA into envB (envB import: envA)?<br></div><div>  I would expect (envB undeclared associationAt: #Foo) becomeForward:  (envA undeclared associationAt: #Foo)...</div>- moving a binding from undeclared to some classPool/sharedPool (PoolDictionary) is completely ignoring the variable scope by now, which may lead to erroneous re-binding.<br><br></div><div>I don&#39;t see obvious solution for the last point (testing that all references to the binding are reachable by the defining class scope thru methodDictionary and subclasses methodDictionary?).<br></div><div>For PoolDictionary, it&#39;s even more tough (going thru all classes sharing this poolDictionary).<br></div><br>I didn&#39;t see any attempt at handling the case when both environment A &amp; B declare a variable Foo, and environment C imports both A and B...<br></div>This is another problem but may lead to other requirements on undeclared handling.<br></div><div class="gmail_extra"><br><div class="gmail_quote">2016-10-25 10:30 GMT+02:00 Nicolas Cellier <span dir="ltr">&lt;<a href="mailto:nicolas.cellier.aka.nice@gmail.com" target="_blank">nicolas.cellier.aka.nice@gmail.com</a>&gt;</span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br>    &quot;Create a foreign environment importing all from Smalltalk globals&quot;<br>    foreign := Environment withName: #Foreign.<br>    foreign exportSelf.<br>    foreign import: Smalltalk globals.<br><br>    &quot;Bind a new global&quot;<br>    fooKey := #ClassVarScopeFoo.<br>    fooValue := Smalltalk globals at: fooKey put: Object basicNew.<br>    fooBinding := Smalltalk globals bindingOf: fooKey.<br>    self assert: (foreign bindingOf: fooKey) == fooBinding.<br><br>    &quot;Unbind the global: it is moved to, and shared by both undeclared&quot;<br>    Smalltalk globals removeKey: fooKey.<br>    self assert: (Smalltalk globals undeclared associationAt: fooKey) == fooBinding.<br>    self assert: (foreign undeclared associationAt: fooKey) == fooBinding.<br><br>    &quot;Create a class var: the undeclared binding is moved to classPool.<br>    This is questionable, it was a global with potentially larger/different scope.&quot;<br>    parent := Object<br>        subclass: #ClassVarScopeParent<br>        instanceVariableNames: &#39;&#39;<br>        classVariableNames: &#39;&#39;<br>        poolDictionaries: &#39;&#39;<br>        category: &#39;Dummy-Tests-Class&#39;.<br>    child := parent<br>        subclass: #ClassVarScopeChild<br>        instanceVariableNames: &#39;&#39;<br>        classVariableNames: &#39;ClassVarScopeFoo&#39;<br>        poolDictionaries: &#39;&#39;<br>        category: &#39;Dummy-Tests-Class&#39;.<br>    self assert: (child classPool associationAt: fooKey) == fooBinding.<br>    <br>    &quot;The global is no more in Smalltalk globals undeclared&quot;<br>    self assert: (Smalltalk globals undeclared includesKey: fooKey) not.<br>    &quot;But it is still in foreign undeclared&quot;<br>    self assert: (foreign undeclared associationAt: fooKey) == fooBinding.<br>    <br>    &quot;Rebind a new global&quot;<br>    fooValue := Smalltalk globals at: fooKey put: Object basicNew.<br>    globalFooBinding := Smalltalk globals bindingOf: fooKey.<br>    <br>    &quot;The binding has been removed from foreign undeclared&quot;<br>    self assert: (foreign undeclared includesKey: fooKey) not.<br>    self assert: (foreign bindingOf: fooKey) == globalFooBinding.<br>    <br>    &quot;But because #showBinding: did use a becomeForward: the class pool and global bindings are now surprisingly fused.<br>    That explains that a foreign environment importing Smalltalk globals is enough to make ClassVarScopeTest fail&quot;<br>    self assert: globalFooBinding == fooBinding.<br>    self assert: (child classPool associationAt: fooKey) == globalFooBinding.<br>    <br>    &quot;save our souls&quot;<br>    classes := { child. parent }.<br>    child := parent := nil.<br>    classes do: [ :each |<br>        each<br>            removeFromChanges;<br>            removeFromSystemUnlogged ].<br>    classes := nil.<br>    Smalltalk globals removeKey: fooKey.<br>    foreign destroy.<br></div>
</blockquote></div><br></div>