<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->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'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's even more tough (going thru all classes sharing this poolDictionary).<br></div><br>I didn't see any attempt at handling the case when both environment A & 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"><<a href="mailto:nicolas.cellier.aka.nice@gmail.com" target="_blank">nicolas.cellier.aka.nice@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br> "Create a foreign environment importing all from Smalltalk globals"<br> foreign := Environment withName: #Foreign.<br> foreign exportSelf.<br> foreign import: Smalltalk globals.<br><br> "Bind a new global"<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> "Unbind the global: it is moved to, and shared by both undeclared"<br> Smalltalk globals removeKey: fooKey.<br> self assert: (Smalltalk globals undeclared associationAt: fooKey) == fooBinding.<br> self assert: (foreign undeclared associationAt: fooKey) == fooBinding.<br><br> "Create a class var: the undeclared binding is moved to classPool.<br> This is questionable, it was a global with potentially larger/different scope."<br> parent := Object<br> subclass: #ClassVarScopeParent<br> instanceVariableNames: ''<br> classVariableNames: ''<br> poolDictionaries: ''<br> category: 'Dummy-Tests-Class'.<br> child := parent<br> subclass: #ClassVarScopeChild<br> instanceVariableNames: ''<br> classVariableNames: 'ClassVarScopeFoo'<br> poolDictionaries: ''<br> category: 'Dummy-Tests-Class'.<br> self assert: (child classPool associationAt: fooKey) == fooBinding.<br> <br> "The global is no more in Smalltalk globals undeclared"<br> self assert: (Smalltalk globals undeclared includesKey: fooKey) not.<br> "But it is still in foreign undeclared"<br> self assert: (foreign undeclared associationAt: fooKey) == fooBinding.<br> <br> "Rebind a new global"<br> fooValue := Smalltalk globals at: fooKey put: Object basicNew.<br> globalFooBinding := Smalltalk globals bindingOf: fooKey.<br> <br> "The binding has been removed from foreign undeclared"<br> self assert: (foreign undeclared includesKey: fooKey) not.<br> self assert: (foreign bindingOf: fooKey) == globalFooBinding.<br> <br> "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"<br> self assert: globalFooBinding == fooBinding.<br> self assert: (child classPool associationAt: fooKey) == globalFooBinding.<br> <br> "save our souls"<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>