<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><meta name=Generator content="Microsoft Word 15 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:Helvetica;
        panose-1:0 0 0 0 0 0 0 0 0 0;}
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:70.85pt 70.85pt 2.0cm 70.85pt;}
div.WordSection1
        {page:WordSection1;}
--></style></head><body lang=DE-CH link=blue vlink=purple style='word-wrap:break-word'><div class=WordSection1><p class=MsoNormal><span lang=DE style='mso-fareast-language:EN-US'>Why?<o:p></o:p></span></p><p class=MsoNormal><span lang=DE style='mso-fareast-language:EN-US'>Jörg<o:p></o:p></span></p><p class=MsoNormal><span lang=DE style='mso-fareast-language:EN-US'><o:p> </o:p></span></p><div style='border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm'><p class=MsoNormal><b><span style='font-size:12.0pt;color:black'>Von: </span></b><span style='font-size:12.0pt;color:black'>Oberon <oberon-bounces@lists.inf.ethz.ch> im Auftrag von Luca Boasso <luke.boasso@gmail.com><br><b>Antworten an: </b>ETH Oberon and related systems <oberon@lists.inf.ethz.ch><br><b>Datum: </b>Dienstag, 27. Oktober 2020 um 16:08<br><b>An: </b>ETH Oberon and related systems <oberon@lists.inf.ethz.ch><br><b>Betreff: </b>Re: [Oberon] Protocols (interfaces) in Oberon-2<o:p></o:p></span></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><div><p class=MsoNormal>The problem is not the syntax but the semantic.<o:p></o:p></p></div><div><p class=MsoNormal>This should be allowed:<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal><span style='font-family:"Courier New"'>      VAR i: I; r: R;<br>        inc: Incrementer; <br><br>      inc := i;<br>      inc := r;</span><o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div></div><p class=MsoNormal><o:p> </o:p></p><div><div><p class=MsoNormal>On Tue, Oct 27, 2020 at 10:02 AM Jörg <<a href="mailto:joerg.straube@iaeth.ch">joerg.straube@iaeth.ch</a>> wrote:<o:p></o:p></p></div><blockquote style='border:none;border-left:solid #CCCCCC 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-right:0cm'><div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>Luca</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US> </span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>I fully agree that with your proposed INTERFACE syntax the setup of the environment is much easier.</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>My proposed MODULE structure is more cumbersome to setup.</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US> </span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>After you set up everything (implemented all needed interface procedures…), is there a big difference whether you write </span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>in your syntax</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US style='font-family:"Courier New"'>  NEW(i);<br>  i.h := 3;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US style='font-family:"Courier New"'>  inc := i;<br>  inc.IncBy2;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US> </span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>or in my syntax</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US style='font-family:"Courier New"'> New(i);<br>i.h := 3;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US style='font-family:"Courier New"'>i.inc.IncBy2(i);</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US> </span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>br</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>Joerg </span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US> </span><o:p></o:p></p><div style='border:none;border-top:solid windowtext 1.0pt;padding:3.0pt 0cm 0cm 0cm;border-color:currentcolor currentcolor'><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><b><span style='font-size:12.0pt;color:black'>Von: </span></b><span style='font-size:12.0pt;color:black'>Oberon <<a href="mailto:oberon-bounces@lists.inf.ethz.ch" target="_blank">oberon-bounces@lists.inf.ethz.ch</a>> im Auftrag von Luca Boasso <<a href="mailto:luke.boasso@gmail.com" target="_blank">luke.boasso@gmail.com</a>><br><b>Antworten an: </b>ETH Oberon and related systems <<a href="mailto:oberon@lists.inf.ethz.ch" target="_blank">oberon@lists.inf.ethz.ch</a>><br><b>Datum: </b>Dienstag, 27. Oktober 2020 um 15:37<br><b>An: </b>ETH Oberon and related systems <<a href="mailto:oberon@lists.inf.ethz.ch" target="_blank">oberon@lists.inf.ethz.ch</a>><br><b>Betreff: </b>Re: [Oberon] Protocols (interfaces) in Oberon-2</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>Although this is a solution to the problem, it doesn't buy you much because all generic signatures must have the type <b><span lang=EN-US>Data.Any</span></b><span lang=EN-US>. </span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>To lift the limitation that the clients must know about the module <b>Data</b> we could extend Oberon-07 to support Component Pascal's ANYPTR type, defined as</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US style='color:blue'>ANYREC and ANYPTR<br>Each base record is implicitly regarded as an extension of the new abstract standard type ANYREC,<br>even if it is declared without explicit base type. ANYREC is an empty record that forms the root of all<br>record type hierarchies. ANYPTR is a new standard type that corresponds to a POINTER TO<br>ANYREC.<br>These new types make it easier to achieve interoperability between independently developed<br>frameworks, by allowing completely generic parameters.</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US style='font-family:"Courier New";color:blue'>The following pseudo definitions can be assumed:<br>ANYREC = ABSTRACT RECORD END;<br>ANYPTR = POINTER TO ANYREC;<br>PROCEDURE (a: ANYPTR) FINALIZE-, NEW, EMPTY;</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>But regardless, the beauty of interfaces is to be able to do something like the following:<o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-family:"Courier New"'>MODULE Demo;<br>  VAR W: Texts.Writer;<br>  TYPE<br>    I* = POINTER TO IDesc;<br>    IDesc* = RECORD<br>        h: INTEGER<br>    END ;<br><br>    R* = POINTER TO RDesc;<br>    RDesc* = RECORD<br>        h: REAL<br>    END ;<br><br>    Stringer* = INTERFACE<br>        PROCEDURE ToString* (VAR a: ARRAY OF CHAR) ;<br>    END ;<br><br>    Incrementer* = INTERFACE <br>      PROCEDURE IncBy2*();<br>    END ;<br><br>  PROCEDURE ( i : I ) ToString* (VAR a: ARRAY OF CHAR) ;<br>  BEGIN a := "integer"<br>  END ToString;<br><br>  PROCEDURE ( r : R ) ToString* (VAR a: ARRAY OF CHAR) ;<br>  BEGIN a := "real"<br>  END ToString;<br> <br>  PROCEDURE ( i : I ) IncBy2*;<br>  BEGIN i.h := i.h + 2<br>  END IncBy2;<br><br>  PROCEDURE ( r : R ) IncBy2*;<br>  BEGIN  r.h := r.h + 2.0<br>  END IncBy2;<br> <br>  PROCEDURE CallStringer(s: Stringer);<br>      VAR t: ARRAY 32 OF CHAR<br>  BEGIN<br>      s.ToString(t);<br>      Texts.WriteString(W,t);<br>  END CallStringer;<br> <br>  PROCEDURE Test*;<br>      VAR i: I; r: R; ;<br>        s: Stringer; <br>        inc: Incrementer;<br>  BEGIN <br>      NEW(i); NEW(r);<br>      i.h := 3;<br>      r.h := 7.5;<br>      (*<br>        The assignment below allows for structural type compatibility between a <br>        record (i) and an interface (s). Interfaces can only have PROCEDUREs in<br>        their definition, if a record implements the set of PROCEDUREs of a <br>        interface, it can then be assigned to it. <br>        Any record implements the empty interface: INTERFACE END;<br>        This is how the Go language works.<br>      *)<br>      inc := i;<br>      inc.IncBy2;<br>      inc := r;<br>      inc.IncBy2;<br>      CallStringer(i);  (* this is an assignment to the formal parameter*)       <br>      CallStringer(r);  (* this is an assignment to the formal parameter*)       <br>      (* <br>        Alternatively we could still allow for nominal type compatibility <br>        forcing the user to specify that a record implements a set of <br>        interfaces:<br>         <br>          I* = POINTER TO IDesc;<br>          IDesc* = RECORD(Stringer, Incrementer)<br>              h: INTEGER<br>          END ;<br>          <br>        The fact that a record implements an interface is explicit. This is<br>        how Java does it. Extending from multiple interface types does not <br>        bring the complexity and pitfalls of multiple inheritance.<br>        To simplify the language in both cases, structural or nominal type <br>        compatibility, we should drop the ability to extend RECORDs with other<br>        records. Only INTERFACEs are allowed because we want only to extend <br>        behavior not data. If you also need the data simply add compose <br>        records as fields.<br>      *)<br>  END Test;<br>END Demo.</span><o:p></o:p></p></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p><div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>On Mon, Oct 26, 2020 at 2:29 PM Charles Perkins <<a href="mailto:chuck@kuracali.com" target="_blank">chuck@kuracali.com</a>> wrote:<o:p></o:p></p></div><blockquote style='border:none;border-left:solid windowtext 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-top:5.0pt;margin-right:0cm;margin-bottom:5.0pt;border-color:currentcolor currentcolor currentcolor rgb(204,204,204)'><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>Hmm...<o:p></o:p></p><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>Everything that implements an interface must be a descendant of Module Data but Data is empty, therefore its signature never needs to change. The use of an interface is checked in the CASE statement and cast there to the interface needed by the client. I think multiple interfaces can be implemented by successively extending Data. This could do it!<o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>I am going to try to use this, thank you <span style='font-size:10.5pt;font-family:Helvetica;color:#202124;letter-spacing:.15pt'>Jörg for your patience with me.</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:10.5pt;font-family:Helvetica;color:#202124;letter-spacing:.15pt'>Cheers,</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:10.5pt;font-family:Helvetica;color:#202124;letter-spacing:.15pt'>Chuck</span><o:p></o:p></p></div></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p><div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>On Mon, Oct 26, 2020 at 11:42 AM Jörg <<a href="mailto:joerg.straube@iaeth.ch" target="_blank">joerg.straube@iaeth.ch</a>> wrote:<o:p></o:p></p></div><blockquote style='border:none;border-left:solid windowtext 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-top:5.0pt;margin-right:0cm;margin-bottom:5.0pt;border-color:currentcolor currentcolor currentcolor rgb(204,204,204)'><div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>Chuck</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US> </span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>Okay. My proposal in standard Oberon-07 for your new requirement is this:</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US> </span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>MODULE Data;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>TYPE</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>  Any* = POINTER TO Empty;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>  Empty* = RECORD END;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>END Data.</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US> </span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;margin-bottom:12.0pt'><span lang=EN-US>MODULE Jsonify;<br>IMPORT Data;<br>TYPE<br>  Methods* = POINTER TO MDesc;<br>  MDesc* = RECORD<br>    toJSON: PROCEDURE(this: Data.Any);<br>  END;<br>END Jsonify.</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>MODULE myData;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>IMPORT Data;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>TYPE</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>  Tree* = POINTER TO TreeDesc;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>  TreeDesc* = RECORD (Data.Empty)</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>    left, right: Tree;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>    j: Jsonify;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>  END;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>VAR t: Tree;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>PROCEDURE J(t: Data.Any);</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>  BEGIN</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>    CASE t OF Tree: (* implement here your Tree-specific JSON routine *) </span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>    END</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>  END J;</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;margin-bottom:12.0pt'><span lang=EN-US>PROCEDURE New*(VAR t: Tree); BEGIN NEW(t); Jsonify.New(t.j); t.j.toJSON := J END New</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>BEGIN</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> New(t); t.j.toJSON(t)<o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>END myData.</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US> </span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>br</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US>Jörg</span><o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span lang=EN-US> </span><o:p></o:p></p><div style='border:none;border-top:solid windowtext 1.0pt;padding:3.0pt 0cm 0cm 0cm;border-color:currentcolor'><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><b><span style='font-size:12.0pt;color:black'>Von: </span></b><span style='font-size:12.0pt;color:black'>Oberon <<a href="mailto:oberon-bounces@lists.inf.ethz.ch" target="_blank">oberon-bounces@lists.inf.ethz.ch</a>> im Auftrag von Charles Perkins <<a href="mailto:chuck@kuracali.com" target="_blank">chuck@kuracali.com</a>><br><b>Antworten an: </b>ETH Oberon and related systems <<a href="mailto:oberon@lists.inf.ethz.ch" target="_blank">oberon@lists.inf.ethz.ch</a>><br><b>Datum: </b>Montag, 26. Oktober 2020 um 17:03<br><b>An: </b>ETH Oberon and related systems <<a href="mailto:oberon@lists.inf.ethz.ch" target="_blank">oberon@lists.inf.ethz.ch</a>><br><b>Betreff: </b>Re: [Oberon] Protocols (interfaces) in Oberon-2</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>Hi <span style='font-size:10.5pt;font-family:Helvetica;color:#202124;letter-spacing:.15pt'>Jörg and other interested people,</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>There is just one piece missing I think for the usage of Interfaces that I am looking for. I would like to be able to write a routine that doesn't know what Data is (in the provided example) but can still hold a pointer to it or to anything else that implements the JSONify interface (and not anything that doesn't implement the JSONify interface) and can call it's ToJSON procedure.<o:p></o:p></p><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>In my previous reply I incorrectly thought that a record in Oberon can be an extension of two base records, which is not right, and not what Jörg is presenting. <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>Apologies for my confusion,<o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>Chuck<o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p><div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>On Mon, Oct 26, 2020 at 7:37 AM Charles Perkins <<a href="mailto:chuck@kuracali.com" target="_blank">chuck@kuracali.com</a>> wrote:<o:p></o:p></p></div><blockquote style='border:none;border-left:solid windowtext 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-top:5.0pt;margin-right:0cm;margin-bottom:5.0pt;border-color:currentcolor currentcolor currentcolor rgb(204,204,204)'><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>Hi <span style='font-size:10.5pt;font-family:Helvetica;color:#202124;letter-spacing:.15pt'>Jörg,</span><o:p></o:p></p><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:10.5pt;font-family:Helvetica;color:#202124;letter-spacing:.15pt'>With this example I think I understand how Oberon can in fact already do what I want in composing Interfaces. In Wirthian fashion the mechanism is explicit rather than implicit. I had not made the mental jump to how a record may be based on more than one base record... with that, everything else falls into place.</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:10.5pt;font-family:Helvetica;color:#202124;letter-spacing:.15pt'>I observe that this means that interfaces are 'opt in' rather than automatic based on just matching a subset of method names, but that's typical and arguably more safe anyway.</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:10.5pt;font-family:Helvetica;color:#202124;letter-spacing:.15pt'>I'm going to think on this some more.</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:10.5pt;font-family:Helvetica;color:#202124;letter-spacing:.15pt'>Thank you very much for taking the time to illustrate this to us.</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:10.5pt;font-family:Helvetica;color:#202124;letter-spacing:.15pt'>Best,</span><o:p></o:p></p></div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:10.5pt;font-family:Helvetica;color:#202124;letter-spacing:.15pt'>Chuck</span><o:p></o:p></p><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div></div></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p><div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>On Sun, Oct 25, 2020 at 11:55 PM Jörg <<a href="mailto:joerg.straube@iaeth.ch" target="_blank">joerg.straube@iaeth.ch</a>> wrote:<o:p></o:p></p></div><blockquote style='border:none;border-left:solid windowtext 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-top:5.0pt;margin-right:0cm;margin-bottom:5.0pt;border-color:currentcolor currentcolor currentcolor rgb(204,204,204)'><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>Chuck<br><br>        > Andreas, in your scheme can you create separate protocols, for example<br>        > "Jsonify" with the method ToJSON and a different protocol "Persistify" with<br>        > the methods "Store" and "Load", and have other records implement one or the<br>        > other or neither or both?<br><br>Here my proposal for doing this in standard Oberon-07.<br>In the previous mail, I separated interface/protocol and implementation for clarity. The same should be done here. For brevity, I combined the two here.<br><br>MODULE Data;<br>(* Definition of whatever your internal data structure looks like. Here just an example *)<br>TYPE<br>  Tree* = POINTER TO TreeDesc;<br>  TreeDesc* = RECORD val*: ARRAY 15 OF CHAR; left*, right*: Tree END<br>END Data.<br><br>MODULE Jsonify;<br>IMPORT Data;<br>TYPE<br>  Methods* = POINTER TO MDesc;<br>  MDesc* = RECORD<br>    toJSON: PROCEDURE(this: Data.Tree);<br>  END;<br>  (* empty or default implementation *)<br>  PROCEDURE J(this: Data.Tree); END J;<br>  PROCEDURE New*(VAR m: Method); BEGIN NEW(m); m.toJSON := J END;<br>END Jsonify.<br><br>MODULE Persistify;<br>IMPORT Data;<br>TYPE<br>  Methods* = POINTER TO MDesc;<br>  MDesc* = RECORD<br>    Load: PROCEDURE(VAR this: Data.Tree);<br>    Store: PROCEDURE(this: Data.Tree)<br>  END;<br>  (* empty or default implementation *)<br>  PROCEDURE L(VAR this: Data.Tree); BEGIN this := NIL END L;<br>  PROCEDURE S(this: Data.Tree); END S;<br>  PROCEDURE New*(VAR m: Methods); BEGIN NEW(m); m.Load := L; m.Store := S END Init;<br>END Persistify.<br><br>Here now a module using both interfaces/protocols and overwrite even one persist procedure with an own version, if wanted. <br>MODULE Usage;<br>IMPORT Data, Jsonify, Persistify;<br>TYPE<br>  User = RECORD (Data.Tree)<br>    j: Jsonify;<br>    p: Persistify<br>  END;<br>VAR u: User;<br>PROCEDURE myLoad(this: Data.Tree); (* implement your version of persist Load *) END myLoad;<br>PROCEDURE New*(VAR u: User);<br>  BEGIN NEW(u); Jsonify.New(u.j); Persistify.New(u.p); u.p.Load := myLoad END New;<br><br>BEGIN<br>  New(u); u.j.toJSON(u); u.p.Load(u) (* this calls my version *)<br>END Usage.<br><br>Adding the qualifiers "j" and "p" circumvents the ambiguity in case the two interfaces defined methods with the same name.<br><br>br<br>Jörg<br><br><br><br>--<br><a href="mailto:Oberon@lists.inf.ethz.ch" target="_blank">Oberon@lists.inf.ethz.ch</a> mailing list for ETH Oberon and related systems<br><a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon" target="_blank">https://lists.inf.ethz.ch/mailman/listinfo/oberon</a><o:p></o:p></p></blockquote></div></blockquote></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>-- <a href="mailto:Oberon@lists.inf.ethz.ch" target="_blank">Oberon@lists.inf.ethz.ch</a> mailing list for ETH Oberon and related systems <a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon" target="_blank">https://lists.inf.ethz.ch/mailman/listinfo/oberon</a> <o:p></o:p></p></div></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>--<br><a href="mailto:Oberon@lists.inf.ethz.ch" target="_blank">Oberon@lists.inf.ethz.ch</a> mailing list for ETH Oberon and related systems<br><a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon" target="_blank">https://lists.inf.ethz.ch/mailman/listinfo/oberon</a><o:p></o:p></p></blockquote></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>--<br><a href="mailto:Oberon@lists.inf.ethz.ch" target="_blank">Oberon@lists.inf.ethz.ch</a> mailing list for ETH Oberon and related systems<br><a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon" target="_blank">https://lists.inf.ethz.ch/mailman/listinfo/oberon</a><o:p></o:p></p></blockquote></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>-- <a href="mailto:Oberon@lists.inf.ethz.ch" target="_blank">Oberon@lists.inf.ethz.ch</a> mailing list for ETH Oberon and related systems <a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon" target="_blank">https://lists.inf.ethz.ch/mailman/listinfo/oberon</a> <o:p></o:p></p></div></div><p class=MsoNormal>--<br><a href="mailto:Oberon@lists.inf.ethz.ch" target="_blank">Oberon@lists.inf.ethz.ch</a> mailing list for ETH Oberon and related systems<br><a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon" target="_blank">https://lists.inf.ethz.ch/mailman/listinfo/oberon</a><o:p></o:p></p></blockquote></div><p class=MsoNormal>-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon <o:p></o:p></p></div></body></html>