[Oberon] Oberon for a C++ user.
Skulski, Wojciech
skulski at pas.rochester.edu
Tue Oct 4 00:09:02 CEST 2016
Doug:
this discussion let me recognize that procedure variables are fundamentally different from regular variables in the following sense.
Procedures variables have two attribute: value and validity. These two are independent in case of procedures variables, because they are not variables, but handlers.
Regular variables have one attribute: value. The value is trivially valid. (With a minor exception of floating point variables where some values are not-a-number, which however is well understood and often useful.) The validity of a regular variable is trivial, because the regular variable is passive.
The procedure variable is different. It has both a value (an address to jump to) and validity. The procedure variable's value is a perfectly valid address, unless it points at the non-existing memory segment. This is well known and often taken care of by the memory protection unit (MPU). Oberon does not stipulate using the MPU because Oberon makes the promise that the language is safe enough to get away without the MPU.
At the point of assignment procvar := Mod.Proc, the procvar gets both the value and the positive validity. Later on, someone (the programmer) makes the validity to become invalid, which however does not propagate back to the procvar's value.
The Oberon System makes the promise that once valid, always valid. However, the Oberon System breaks this promise by allowing the validity to disappear behind the procvar's back.
You can also look at it from the point of view of the client/ server. At the point of assignment procvar := Mod.Proc, the client gets the asset and the server Mod makes the promise. When the server is unloaded, it breaks the promise without telling the client "I am gone, do not rely on my assets". The client thinks it still has a good asset, tries to use it, and it gets duped. The client is perfectly innocent. It was the server who broke the contract.
I am proposing that we make a clear case. The procedure variable are not a variable, because it is characterized by a pair of attributes (value, validity). Both attributes need be handled, because they are independent from each other. The regular variable has only one attribute, namely a value. The other attribute is trivially fulfilled and it thus does not require any handling.
Based on this consideration, a physicist would conclude: saying that a procedure variable is the same as a regular variable is akin to saying that a vector is the same as a scalar. No, it is not. A vector is distinct from a scalar because the number of dimensions is different. Here we have a similar case: two independent attributes versus one.
If this sounds scholarly, then I would say it is not. We need to understand the fundamental reason why there is a potential for system corruption and get rid of it in some elegant but effective way. IMO it can only help if we make a clearcut distinction between two classes of objects which are fundamentally different from each other.
W.
________________________________________
From: Oberon [oberon-bounces at lists.inf.ethz.ch] on behalf of Douglas G. Danforth [danforth at greenwoodfarm.com]
Sent: Monday, October 3, 2016 4:55 PM
To: ETH Oberon and related systems
Subject: Re: [Oberon] Oberon for a C++ user.
W,
I like it.
The reference counting can be quite complex.
IF module A is imported by B, C, ... and A exports a procedure variable
(or routine that sets a procedure variable) then only if B, C, ... actually
assign a value to the procedure variable of A does the problem arise.
-Doug
On 10/3/2016 12:07 AM, Skulski, Wojciech wrote:
> Andreas:
>
> the problem IMHO is in the operator :=, which is overloaded. The procedure variables are not a variables in the usual sense. The operator := should not apply to them.
>
> A regular variable has a value. The value is passive. It gets acted upon by a client. The variable is not doing anything on its own. Somebody is doing something with the variable (somebody is using its value for some goal).
>
> IF var1 = var2 THEN... (*passive role of the variables*)
>
> The procedure variable has a value (the address to jump to), and also a behavior. The value is passive, but the behavior is active. The value is retained after unloading the implementation, but the behavior is damaged. This is the problem.
>
> The value (the address) is not that important. Yes, you can use it in comparisons:
>
> IF proc1 = proc2 THEN... (*passive role of the procedure variables*)
>
> Note that after unloading the implementations of the proc1 and proc2, you can still make the comparison. Both proc1 and proc2 are perfectly valid in the passive sense. Their code is gone, but their passive values (addresses) are perfectly OK.
>
> But this is not why procedure variables are important. We want their behaviors. And this gets damaged upon unloading.
>
> In order to cure the problem, the operator :=should not be permitted with procedure variables. There needs to be another, separate operator which will assign procedure variables and also take care of the reference counting.
>
> ASSIGN (procvar, Mod.Proc)
>
> I think that separating both operators := and ASSIGN will make sense, because regular variables are not posing the problem which procedure variables are posing.
>
> The counterpart of ASSIGN would be RETRACT (or some better name). Since you re not allowed to use := with procedure variables, you could not write
>
> procvar := NIL; (*not allowed*)
>
> You would have to say
>
> RETRACT (procvar); (*takes care of the references*)
>
> I hope this proposition makes sense.
>
> W.
>
> ----------------------------
>
> Chris, Joerg:
>
> that is exactly the problem: assigning a procedure of a *client* module to a procedure variable of an *imported* module, and then unloading the client module - leaving the procedure variable in the imported module dangling.
>
> Assigning a procedure of a client module to a variable of an imported "base" module is in fact the standard way the Oberon system itself employs procedure variables to implement the viewer system in an object-oriented style.
>
> For example, module TextFrames (the client) installs a handler (procedure TextFrames.Handle) in the field F.handle of text frame F (see TextFrames.NewText and TextFrames.Open for the details), where the record field F.handle is declared as a procedure variable in the "base" module Viewers (see Viewers.ViewerDesc), which also manages the viewer data structure (see procedure Viewers.Open).
>
> Except that of course in the case of the Oberon system, the "client" module TextFrames *never* gets unloaded, so this is not a problem there. Thus, the burden is on the user to make sure that such modules never get unloaded.
>
> It is of course possible to implement a "procedure variable" counter - in analogy to the "module counter" employed in Oberon: each time an assignment to a procedure variable is made, the counter gets increased. But that would require changing the code generator compiler for assignments, and the module loader (Modules.Load) and unloader (Modules.Free). But I would refrain from introducing such complexity to the compiler and runtime system.
>
> Andreas
>
> Chris Burrows chris at cfbsoftware.com <mailto:oberon%40lists.inf.ethz.ch?Subject=Re:%20Re%3A%20%5BOberon%5D%20Oberon%20for%20a%20C%2B%2B%20user.&In-Reply-To=%3C000a01d21ba8%24b97dc9d0%242c795d70%24%40cfbsoftware.com%3E>
>
> ________________________________
>
>> Joerg,
>>
>> OK - you may well be onto something here but it is incomplete as it is. Something has to
>> import Square so that the module body is executed, or you need an exported procedure in
>> Square that is called from the OS.
>> Note: there are a couple of semicolons missing and Init must be exported.
>> Chris.
>> -----Original Message-----
>> From: Jörg Straube [mailto:joerg.straube at iaeth.ch<https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.inf.ethz.ch_mailman_listinfo_oberon&d=CwMFaQ&c=kbmfwr1Yojg42sGEpaQh5ofMHBeTl9EI2eaqQZhHbOU&r=uUiA_zLpwaGJIlq-_BM9w1wVOuyqPwHi3XzJRa-ybV0&m=UHr5AP3cXC2ZAXacD2dYANUhpxDnR6gWosSpUd2oaRw&s=TWgxIZxS5z7mpZJDUj92ydjRoic3rLYdp0iN4Zb0ngQ&e=>]
>> Sent: Saturday, 1 October 2016 2:22 PM
>> To: chris at cfbsoftware.com<https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.inf.ethz.ch_mailman_listinfo_oberon&d=CwMFaQ&c=kbmfwr1Yojg42sGEpaQh5ofMHBeTl9EI2eaqQZhHbOU&r=uUiA_zLpwaGJIlq-_BM9w1wVOuyqPwHi3XzJRa-ybV0&m=UHr5AP3cXC2ZAXacD2dYANUhpxDnR6gWosSpUd2oaRw&s=TWgxIZxS5z7mpZJDUj92ydjRoic3rLYdp0iN4Zb0ngQ&e=>; ETH Oberon and related systems
>> Subject: Re: [Oberon] Oberon for a C++ user.
>>
>> Chris
>>
>> Here a possble example that might cause issues:
>>
>> MODULE Figure;
>> TYPE
>> DrawProc = PROCEDURE;
>> Figure = POINTER TO FigureDesc;
>> FigureDesc = RECORD
>> next: Figure;
>> draw: DrawProc
>> END;
>> VAR list: Figure;
>> PROCEDURE Init(d: DrawProc)
>> VAR f: Figure;
>> BEGIN
>> NEW(f); f.next := list; list := f;
>> f.draw := d
>> END Init;
>> BEGIN list:= NIL END Figure.
>>
>> MODULE Square;
>> IMPORT Figure;
>> PROCEDURE DrawSquare;
>> BEGIN (* do what ever you
>> need to do to draw a square *)
>> END DrawSquare
>> BEGIN
>> Figure.Init(DrawSquare)
>> END Square.
>>
>> Now you could run Square and unload Square. The list in Figure has a
>> reference to unloaded code.
>>
>> J rg
>>
> --
> Oberon at lists.inf.ethz.ch mailing list for ETH Oberon and related systems
> https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.inf.ethz.ch_mailman_listinfo_oberon&d=CwIF-g&c=kbmfwr1Yojg42sGEpaQh5ofMHBeTl9EI2eaqQZhHbOU&r=uUiA_zLpwaGJIlq-_BM9w1wVOuyqPwHi3XzJRa-ybV0&m=2hCB-kYQ6nAwqgBQyA2wJiz_nEJx2nZM1lRobiKp7aA&s=R4cllNBWvXw007qPPb3yL6ptNSRN7MT7SK5adx7jGag&e=
>
--
Oberon at lists.inf.ethz.ch mailing list for ETH Oberon and related systems
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.inf.ethz.ch_mailman_listinfo_oberon&d=CwIF-g&c=kbmfwr1Yojg42sGEpaQh5ofMHBeTl9EI2eaqQZhHbOU&r=uUiA_zLpwaGJIlq-_BM9w1wVOuyqPwHi3XzJRa-ybV0&m=2hCB-kYQ6nAwqgBQyA2wJiz_nEJx2nZM1lRobiKp7aA&s=R4cllNBWvXw007qPPb3yL6ptNSRN7MT7SK5adx7jGag&e=
More information about the Oberon
mailing list