<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div>Felix,</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">Not sure I missed the point. I believe this *should* be the expected behavior. In my code, the type test "emitted" by the "new" module are only to be applied to "new" instances. So for all practical purposes these *are* different types, yes. And the modules *are* different (except that they happened to have shared the same name).</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">If it is your intention to make the type test in the "new" module return also TRUE when applied to instances created by the "old" module (and vice versa), then indeed this would require a different implementation. Agree with that of course.</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">I have actually implemented THAT as well in a variant of Experimental Oberon. It is not difficult (the compiler needs to emit different code for type tests - code that simply runs through all module "versions", old and new, and then performs the type test which is a simple address comparison, and it's easy to know from the module list which modules "belong together" version-wise).</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">But I have refrained from including that in the published version of Experimental Oberon, for several reasons:</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">1. It makes type tests more expensive</div><div id="AppleMailSignature">2. Keeping "old" and "new" separate appears to be the cleaner approach. As you said, it's no drama, really, and programmer can always handle it as well (eg by just adding another "id" field or something).</div><div id="AppleMailSignature">3. It would only be a real solution if one formally introduces the notion of a "version" of a module - but that would in turn lead to complex rules on when are two modules considered to be same, what if I *want* multiple versions coexisting - and I didn't see the need for that kind of complexity in the Oberon core - although it's perfectly doable.</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">If you give me a good use case, I may reconsider and publish a variant of EO that handles multiple module versions the way you see them.</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">Multiple versions in memory are mostly occurring during development (so that's not a good use case), but not in production. The only "good" use case I have seen so far is on a server environment in a data center where one might indeed want to have multiple versions of, say, an Oracle database, hosted on the *same* server. But with the advent of virtual machines, even that use case has by and large gone away long time ago.</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">But happy to be proven wrong. With a good use case, I'll publish... </div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">Best,</div><div id="AppleMailSignature">Andreas</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature"><span style="background-color: rgba(255, 255, 255, 0);"><b>Felix Friedrich</b> <a href="mailto:oberon%40lists.inf.ethz.ch?Subject=Re:%20Re%3A%20%5BOberon%5D%20Oberon%20for%20a%20C%2B%2B%20user.&In-Reply-To=%3C18539865-1044-b113-5742-db495c7fa1bb%40inf.ethz.ch%3E" title="[Oberon] Oberon for a C++ user.">felix.friedrich at inf.ethz.ch </a><br><i>Mon Nov 21 08:40:45 CET 2016</i></span><p></p><ul><li><span style="background-color: rgba(255, 255, 255, 0);">Previous message: <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/010180.html">[Oberon] Oberon for a C++ user.</a></span></li><li><span style="background-color: rgba(255, 255, 255, 0);">Next message: <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/008714.html">[Oberon] Non Oberon code in Oberon</a></span></li><li><span style="background-color: rgba(255, 255, 255, 0);"><b>Messages sorted by:</b> <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/date.html#10181">[ date ]</a> <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/thread.html#10181">[ thread ]</a> <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/subject.html#10181">[ subject ]</a> <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/author.html#10181">[ author ]</a></span></li></ul><hr><pre><font face="UICTFontTextStyleBody"><span style="white-space: normal; background-color: rgba(255, 255, 255, 0);">Andreas
Although it is nice that it works like this, your code example misses
the point of the previous code: there are two different variants
coexisting of a singleton object (a module) with the consequence that a
type test or type guard on instances of the "old" module emitted from a
"new" module does not work any more.
Eventually it is not a drama because no practically important examples
seem to exist. Moreover with some indirection on the type descriptors it
would be easy to solve. But for the sake of purity....
Kind regards
Felix
><i> Felix,
</i>><i>
</i>><i> below is the output (under Experimental Oberon) of a modified set of
</i>><i> your modules A, B, and C (source code appended below).
</i>><i>
</i>><i>
</i>><i> It nicely shows that C.Delete selects the "right" module B, i.e.
</i>><i> either the "old B" (here called B*), or the "new B" (here called B).
</i>><i> The type descriptors and the code of module B* (removed from module
</i>><i> list) is still available in memory.
</i>><i>
</i>><i>
</i>><i> All type tests automatically select the "right" type descriptor and
</i>><i> the "old B" is only removed from memory when no more references from
</i>><i> the remaining modules exist.
</i>><i>
</i>><i>
</i>><i> Andreas
</i>><i>
</i>><i>
</i>><i> COMMAND SEQUENCE (see below for source code of A, B, and C):
</i>><i>
</i>><i> B.Insert 1 ... insert elemt from old B
</i>><i> System.ShowModules ... B is the old B
</i>><i> System.Free B/f ... remove old B from module list, don't
</i>><i> release memorz
</i>><i> System.ShowModules ... B* is the old B
</i>><i> B.Insert 2 ... new B
</i>><i> System.ShowModules ... B* is the old B, B is the new B
</i>><i> C.Delete 1 ... deletes the element created by the old B
</i>><i> C.Delete 2 ... deletes the element created by the old B
</i>><i> C.Init ... clears the data structure rooted in A.root
</i>><i> Modules.Collect ... collects B* (no longer referenced)
</i>><i> System.ShowModules ... module B* no longer in memory
</i>><i>
</i>><i> GENERATED OUTPUT:
</i>><i>
</i>><i> 1) B.Insert 1
</i>><i> insert element from module B module descriptor at 000212C0
</i>><i>
</i>><i> 2) System.ShowModules
</i>><i> B 000212C0 000213D0 0
</i>><i> A 00020F60 00020FDC 1
</i>><i> System 0001CB80 0001D320 0
</i>><i> ...
</i>><i>
</i>><i> 3) System.Free B/f
</i>><i> B unloading: removing from module list (references exist)
</i>><i>
</i>><i> 4) System.ShowModules
</i>><i> *B 000212C0 000213D0 0 (removed from module list)
</i>><i> A 00020F60 00020FDC 1
</i>><i> System 0001CB80 0001D320 0
</i>><i> ...
</i>><i>
</i>><i> 5) B.Insert 2
</i>><i> insert element from module B module descriptor at 00021800
</i>><i>
</i>><i> 6) System.ShowModules
</i>><i> B 00021800 00021910 0
</i>><i> *B 000212C0 000213D0 0 (removed from module list)
</i>><i> A 00020F60 00020FDC 2
</i>><i> System 0001CB80 0001D320 0
</i>><i> ...
</i>><i>
</i>><i> 7) C.Delete 1
</i>><i> type of t is T from module B* module descriptor at 000212C0
</i>><i>
</i>><i> 8) C.Delete 2
</i>><i> type of t is T from module B module descriptor at 00021800
</i>><i>
</i>><i> 9) C.Init + Modules.Collect + System.ShowModules
</i>><i> B 00021800 00021910 0
</i>><i> A 00020F60 00020FDC 2
</i>><i> System 0001CB80 0001D320 0
</i>><i> ...
</i>><i>
</i>><i> ----------------------------------------------------------------------------------------------------
</i>><i>
</i>><i> MODULE A; (*base module managing data structure of base type T*)
</i>><i> TYPE T* = POINTER TO R;
</i>><i> P* = PROCEDURE (t: T);
</i>><i> R* = RECORD i*: INTEGER;
</i>><i> close*: P;
</i>><i> next: T
</i>><i> END ;
</i>><i>
</i>><i> VAR root*: T;
</i>><i>
</i>><i> PROCEDURE Find*(i: INTEGER): T;
</i>><i> VAR t: T;
</i>><i> BEGIN t := root;
</i>><i> WHILE (t # NIL) & (t.i # i) DO t := t.next END ;
</i>><i> RETURN t
</i>><i> END Find;
</i>><i>
</i>><i> PROCEDURE Insert*(t: T);
</i>><i> VAR s: T;
</i>><i> BEGIN s := Find(t.i);
</i>><i> IF s = NIL THEN t.next := root; root := t END
</i>><i> END Insert;
</i>><i>
</i>><i> PROCEDURE Delete*(i: INTEGER);
</i>><i> VAR s, t: T;
</i>><i> BEGIN t := root; s := t;
</i>><i> WHILE (t # NIL) & (t.i # i) DO s := t; t := t.next END ;
</i>><i> IF t # NIL THEN t.close(t);
</i>><i> IF t = root THEN root := NIL ELSE s.next := t.next END
</i>><i> END
</i>><i> END Delete;
</i>><i>
</i>><i> PROCEDURE Init*;
</i>><i> BEGIN root := NIL
</i>><i> END Init;
</i>><i>
</i>><i> BEGIN Init
</i>><i> END A.
</i>><i>
</i>><i> --------------------------------------
</i>><i>
</i>><i> MODULE B; (*client of A, defining extensions of A.T*)
</i>><i> IMPORT A, Modules, Texts, Oberon;
</i>><i> TYPE T* = POINTER TO R;
</i>><i> R* = RECORD (A.R) j: INTEGER END;
</i>><i>
</i>><i> VAR M: Modules.Module;
</i>><i> W: Texts.Writer;
</i>><i>
</i>><i> PROCEDURE Close*(t: A.T);
</i>><i> VAR S: Texts.Scanner;
</i>><i> BEGIN
</i>><i> IF (t IS T) & (M # NIL) THEN
</i>><i> Texts.WriteString(W, "type of t is T from module ");
</i>><i> Texts.WriteString(W, M.name);
</i>><i> Texts.WriteString(W, " module descriptor at "); Texts.WriteHex(W, ORD(M));
</i>><i> Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
</i>><i> END
</i>><i> END Close;
</i>><i>
</i>><i> PROCEDURE Insert*;
</i>><i> VAR S: Texts.Scanner; t: T;
</i>><i> BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);
</i>><i> Texts.Scan(S);
</i>><i> IF S.class = Texts.Int THEN NEW(t); t.i := S.i; t.close := Close;
</i>><i> A.Insert(t);
</i>><i> Texts.WriteString(W, "insert element from module ");
</i>><i> Texts.WriteString(W, M.name);
</i>><i> Texts.WriteString(W, " module descriptor at "); Texts.WriteHex(W, ORD(M));
</i>><i> Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
</i>><i> END
</i>><i> END Insert;
</i>><i>
</i>><i> PROCEDURE Init*;
</i>><i> BEGIN
</i>><i> END Init;
</i>><i>
</i>><i> BEGIN Texts.OpenWriter(W); M := Modules.root;
</i>><i> WHILE (M # NIL) & (M.name # "B") DO M := M.next END
</i>><i> END B.
</i>><i>
</i>><i> --------------------------------------
</i>><i>
</i>><i> ODULE C; (*tool module*)
</i>><i> IMPORT A, Texts, Oberon;
</i>><i>
</i>><i> VAR W: Texts.Writer;
</i>><i>
</i>><i> PROCEDURE Delete*;
</i>><i> VAR S: Texts.Scanner;
</i>><i> BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);
</i>><i> Texts.Scan(S);
</i>><i> IF S.class = Texts.Int THEN A.Delete(S.i) END
</i>><i> END Delete;
</i>><i>
</i>><i> PROCEDURE Init*;
</i>><i> BEGIN
</i>><i> END Init;
</i>><i>
</i>><i> BEGIN Texts.OpenWriter(W)
</i>><i> END C.
</i>><i>
</i>><i> ----------------
</i>><i>
</i>><i>
</i>><i>
</i>><i>
</i>><i> --
</i>><i> <a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon">Oberon at lists.inf.ethz.ch</a> mailing list for ETH Oberon and related systems
</i>><i> <a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon">https://lists.inf.ethz.ch/mailman/listinfo/oberon</a>
</i>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <<a href="http://lists.inf.ethz.ch/pipermail/oberon/attachments/20161121/0e84a2c6/attachment.html">http://lists.inf.ethz.ch/pipermail/oberon/attachments/20161121/0e84a2c6/attachment.html</a>>
</span></font></pre><hr><p></p><ul><li><span style="background-color: rgba(255, 255, 255, 0);">Previous message: <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/010180.html">[Oberon] Oberon for a C++ user.</a></span></li><li><span style="background-color: rgba(255, 255, 255, 0);">Next message: <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/008714.html">[Oberon] Non Oberon code in Oberon</a></span></li><li><span style="background-color: rgba(255, 255, 255, 0);"><b>Messages sorted by:</b> <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/date.html#10181">[ date ]</a> <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/thread.html#10181">[ thread ]</a> <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/subject.html#10181">[ subject ]</a> <a href="http://lists.inf.ethz.ch/pipermail/oberon/2016/author.html#10181">[ author ]</a></span></li></ul><hr><a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon" style="background-color: rgba(255, 255, 255, 0);"><font color="#000000">More information about the Oberon mailing list</font></a><br><br>Sent from my iPhone</div></body></html>