<div>Hello, Chris!</div><div> </div><div><span style="color:#808080;">> It is the latest version of Oberon that I am particularly interested in as I unable to think of a way to break it using normal programming practices.</span></div><div><span style="color:#808080;">> It may well be possible in BlackBox/Component Pascal but as I said, if that is so, the best way to avoid those problems is not to use Procedure variables in BlackBox/Component Pascal. There are better ways of doing the same thing in that language.</span></div><div> </div><div>  The code I'm about to present below doesn't use any procedure variables, only extensible objects, which is the normal use case these days.</div><div>  I don't have access to the "latest" Oberon, whatever that may be these days, so I'm using BlackBox v1.7 recently released by the community.</div><div>  It is up to you to judge whether the same problem can be reproduced in your environment of choice, but my guess is that if it supports module unloading, then it probably can be.</div><div> </div><div>  The sample code below involves four modules, which may seem like a lot, but conceptually the roles of each are clear:</div><div>  SampleObjectDefinition - exports an abstract RECORD type;</div><div>  SampleObjectImplementation - exports a concrete implementation of that type, including a type-bound procedure;</div><div>  SampleObjectUser - retains an instance of the implementation object, which it holds on to using the abstract type. This module can call the implemented method via the abstract declaration;</div><div>  SampleConfigurer - gives a concrete object instance for the SampleObjectUser to hold.</div><div> </div><div><span style="font-family:andale mono,times;">MODULE SampleObjectDefinition;</span></div><div> </div><div><span style="font-family:andale mono,times;">TYPE</span></div><div><span style="font-family:andale mono,times;"><strong>AbstractType</strong>* = POINTER TO ABSTRACT RECORD END;</span></div><div> </div><div><span style="font-family:andale mono,times;">PROCEDURE (self: AbstractType) <strong>DoSomething</strong>*, NEW, ABSTRACT;</span></div><div> </div><div><span style="font-family:andale mono,times;">END SampleObjectDefinition.</span></div><div> </div><div> </div><div> </div><div><span style="font-family:andale mono,times;">MODULE SampleObjectImplementation;</span></div><div> </div><div><span style="font-family:andale mono,times;">IMPORT</span></div><div><span style="font-family:andale mono,times;">SampleObjectDefinition;</span></div><div> </div><div><span style="font-family:andale mono,times;">TYPE</span></div><div><span style="font-family:andale mono,times;"><strong>ConcreteType</strong>* = POINTER TO RECORD (SampleObjectDefinition.AbstractType) END;</span></div><div> </div><div><span style="font-family:andale mono,times;">PROCEDURE (self: ConcreteType) <strong>DoSomething</strong>*;</span></div><div><span style="font-family:andale mono,times;">BEGIN</span></div><div><span style="font-family:andale mono,times;">END DoSomething;</span></div><div> </div><div><span style="font-family:andale mono,times;">END SampleObjectImplementation.</span></div><div> </div><div> </div><div> </div><div><span style="font-family:andale mono,times;">MODULE SampleObjectUser;</span></div><div> </div><div><span style="font-family:andale mono,times;">IMPORT</span></div><div><span style="font-family:andale mono,times;">SampleObjectDefinition; <em>(* This module we can't unload, but SampleObjectImplementation <u>can</u> be unloaded. *)</em></span></div><div> </div><div><span style="font-family:andale mono,times;">VAR</span></div><div><span style="font-family:andale mono,times;">sampleObject: SampleObjectDefinition.AbstractType;</span></div><div> </div><div><span style="font-family:andale mono,times;">PROCEDURE <strong>AssignObjectInstance</strong>* (object: SampleObjectDefinition.AbstractType);</span></div><div><span style="font-family:andale mono,times;">BEGIN</span></div><div><span style="font-family:andale mono,times;">sampleObject := object <em>(* Store object instance without IMPORTing the implementation module. *)</em></span></div><div><span style="font-family:andale mono,times;">END AssignObjectInstance;</span></div><div> </div><div><span style="font-family:andale mono,times;">PROCEDURE <strong>MakeObjectDoSomething</strong>*;</span></div><div><span style="font-family:andale mono,times;">BEGIN</span></div><div><span style="font-family:andale mono,times;">sampleObject.DoSomething <em>(* Use the stored instance, calling the code that could be unloaded. *)</em></span></div><div><span style="font-family:andale mono,times;">END MakeObjectDoSomething;</span></div><div> </div><div><span style="font-family:andale mono,times;">END SampleObjectUser.</span></div><div> </div><div> </div><div> </div><div><span style="font-family:andale mono,times;">MODULE SampleConfigurer;</span></div><div> </div><div><span style="font-family:andale mono,times;">IMPORT</span></div><div><span style="font-family:andale mono,times;">SampleObjectImplementation, SampleObjectUser;</span></div><div> </div><div><span style="font-family:andale mono,times;">PROCEDURE <strong>Setup</strong>*;</span></div><div><span style="font-family:andale mono,times;">VAR</span></div><div><span style="font-family:andale mono,times;">instance: SampleObjectImplementation.ConcreteType;</span></div><div><span style="font-family:andale mono,times;">BEGIN</span></div><div><span style="font-family:andale mono,times;">NEW(instance);</span></div><div><span style="font-family:andale mono,times;">SampleObjectUser.AssignObjectInstance(instance)</span></div><div><span style="font-family:andale mono,times;">END Setup;</span></div><div> </div><div><span style="font-family:andale mono,times;">END SampleConfigurer.</span></div><div> </div><div><span style="font-family:andale mono,times;">^Q SampleConfigurer.Setup</span></div><div><span style="font-family:andale mono,times;">^Q DevDebug.UnloadThis SampleConfigurer SampleObjectImplementation</span></div><div><span style="font-family:andale mono,times;">^Q SampleObjectUser.MakeObjectDoSomething <em>(* TRAP: illegal execution *)</em></span></div><div> </div><div> </div><div>  Only the SampleConfigurer IMPORTs SampleObjectImplementation, so after the Setup both of these modules can be unloaded. After unloading the implementation, any attempt by the SampleObjectUser to call the methods of the object it holds results in a run-time error (trap).</div><div> </div><div><span style="color:#808080;">> However, I wouldn't be surprised if somebody (like yourself :) ) could concoct an extreme pathological example to make it happen. I'm more interested in the sort of accidental usage that an average programmer might trip over.</span></div><div> </div><div>  This sort of failures due to module unloading happen all the time when I develop a visual element in BlackBox: whenever I reload its module after an edit, all the instances currently on screen fail to render and/or start throwing traps, because the framework keeps calling their - now unloaded - methods.</div><div> </div><div>---=====---</div><div>Александр</div>