> 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.
> 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.
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.
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.
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.
The sample code below involves four modules, which may seem like a lot, but conceptually the roles of each are clear:
SampleObjectDefinition - exports an abstract RECORD type;
SampleObjectImplementation - exports a concrete implementation of that type, including a type-bound procedure;
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;
SampleConfigurer - gives a concrete object instance for the SampleObjectUser to hold.
MODULE SampleObjectDefinition;
TYPE
AbstractType* = POINTER TO ABSTRACT RECORD END;
PROCEDURE (self: AbstractType) DoSomething*, NEW, ABSTRACT;
END SampleObjectDefinition.
MODULE SampleObjectImplementation;
IMPORT
SampleObjectDefinition;
TYPE
ConcreteType* = POINTER TO RECORD (SampleObjectDefinition.AbstractType) END;
PROCEDURE (self: ConcreteType) DoSomething*;
BEGIN
END DoSomething;
END SampleObjectImplementation.
MODULE SampleObjectUser;
IMPORT
SampleObjectDefinition; (* This module we can't unload, but SampleObjectImplementation can be unloaded. *)
VAR
sampleObject: SampleObjectDefinition.AbstractType;
PROCEDURE AssignObjectInstance* (object: SampleObjectDefinition.AbstractType);
BEGIN
sampleObject := object (* Store object instance without IMPORTing the implementation module. *)
END AssignObjectInstance;
PROCEDURE MakeObjectDoSomething*;
BEGIN
sampleObject.DoSomething (* Use the stored instance, calling the code that could be unloaded. *)
END MakeObjectDoSomething;
END SampleObjectUser.
MODULE SampleConfigurer;
IMPORT
SampleObjectImplementation, SampleObjectUser;
PROCEDURE Setup*;
VAR
instance: SampleObjectImplementation.ConcreteType;
BEGIN
NEW(instance);
SampleObjectUser.AssignObjectInstance(instance)
END Setup;
END SampleConfigurer.
^Q SampleConfigurer.Setup
^Q DevDebug.UnloadThis SampleConfigurer SampleObjectImplementation
^Q SampleObjectUser.MakeObjectDoSomething (* TRAP: illegal execution *)
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).
> However, I wouldn't be surprised if somebody (like yourself

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.
---=====---
Александр
--
Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems
https://lists.inf.ethz.ch/mailman/listinfo/oberon