[M3devel] M3CG_Ops.Public vs. M3CG.T

Jay K jay.krell at cornell.edu
Thu Sep 27 21:00:30 CEST 2012


One thing I missed is that  IMPORT M3CG;    Give you an M3CG.T that you can only pass around.     Add IMPORT M3CG_Ops I think it was    and then you can make all the method calls on an M3CG.T.    I don't see that the first intermediate step is useful, but oh well. Everyone might as well just IMPORT M3CG_Ops.   It is kind of interesting that "private" and "protected" are kind of available in Modula-3, or at least    one clump therein, by moving part of the interface into a separate file.   I say one clump, because I don't think you can do this:      FooRoot.i3:    TYPE Foo <: ROOT;   Foo1.i3:  TYPE Foo <: OBJECT METHODS    PROCEDURE F1();    END; Foo2.i3:TYPE Foo <: OBJECT METHODSPROCEDURE F2();END; Foo.m3:   REVEAL Foo = OBJECT METHODS    PROCEDURE F1();    PROCEDURE F2();    END;   I think you can only have just:     FooRoot.i3:      TYPE Foo <: ROOT;       Foo1.i3:      TYPE Foo <: OBJECT METHODS        PROCEDURE F1();        END;   Foo.m3:    REVEAL Foo = OBJECT METHODS         PROCEDURE F1();          PROCEDURE F2();     END;      It'd also be useful if you could do like this:       Stream.i3:     Reader = OBJECT METHODS PROCEDURE Read(); END;    Writer = OBJECT METHODS PROCEDURE Write(); END;    TYPE Stream <: Reader;    TYPE Stream <: Writer;   Stream.m3:  REVEAL Stream = OBJECT METHODS    PROCEDURE Read();    PROCEDURE Write();    END; i.e. -- multiple inheritance. I realize you can reveal in multiple linear steps though...which I'm not going to give an example of right now.. so it isn't just "one clump", but if you reveal "multiple clumps", they need to form a linear chain, right? You can't "mix" as I showed for read/write. ?    - Jay
 From: jay.krell at cornell.edu
To: hosking at cs.purdue.edu
Date: Thu, 27 Sep 2012 05:14:27 +0000
CC: m3devel at elegosoft.com
Subject: Re: [M3devel] M3CG_Ops.Public vs. M3CG.T




No. I'm ok with that.

My point is, that basically, there are two really good forms ofinterface that have the right level of revelation and hiding.I don't see much point for in-between.

The two forms..they are kind of canonical C and C++ forms, butthey both map to Modula-3.

One form is a fully opaque type and a bunch of functionsthat take that type as the first parameter.
Like this:
    struct Window_t;        typedef struct Window_t* Window_t;    
    Window_t* Window_Create(...);    /* create is special -- first parameter       isn't Window_t* */      void Window_Close(Window_t*...);        void Window_SetTitle(Window_t*...);        TEXT Window_GetTitle(Window_t*...);    

It maps directly to Modula-3.Though I'm not sure exactly how.

Window.i3:INTERFACE Window;TYPE T <: ROOT;PROCEDURE Close(T);PROCEDURE SetTitle(T, TEXT);PROCEDURE GetTitle(T): TEXT;

The other form is a bunch of pure virtual functions, nodata, no non-virtual functions. This is what COM prescribes.And "Create" is special.

struct Window_t{    virtual void Close() = 0;    virtual void SetTitle(TEXT) = 0;    virtual TEXT GetTitle() = 0;};

Window_t* Window_Create(...);
This maps well to Modula-3 as well:
Window.i3:T <: OBJECT  METHODS    PROCEDURE Close();    PROCEDURE SetTitle(TEXT);    PROCEDURE GetTitle(): TEXT;END;

The in-between, which I'm not sure is all that worthwhile,is where C++ offers "protected", and "worse", "private".Really "private" doesn't belong in a header.

In the case of M3CG, I don't think we have any need for in-between.I think currently clients either know it is <: ROOT or <: Ops.Public.

I don't see the point in hiding <: Ops.Public.You might as well let every client know that.They just pass them around by value/reference, and not callany methods/member-functions, but I don't see that hidingthem helps anything.

Typical "operating system" interfaces look like what I showed first,except that Window_t* is replaced by "int" or "void*". Which I think ismostly inferior. void* at least allows for basically the same implementationstrategies, including casting it to int and indexing into a table, buthaving different pointer types allows for a little bit of type-safetyin the clients (i.e. avoiding passing a Windows_t* to File_Read).


 - Jay



From: hosking at cs.purdue.edu
Date: Wed, 26 Sep 2012 15:53:26 -0400
To: jay.krell at cornell.edu
CC: m3devel at elegosoft.com
Subject: Re: [M3devel] M3CG_Ops.Public vs. M3CG.T

Are you saying that you don’t like importing M3CG as well as M3CG_Ops?



On Sep 26, 2012, at 3:30 PM, Jay <jay.krell at cornell.edu> wrote:Ok but this seems not great..

 - Jay (briefly/pocket-sized-computer-aka-phone)
On Sep 26, 2012, at 8:58 AM, Antony Hosking <hosking at cs.purdue.edu> wrote:

Yes, M3CG.T is the most abstract type.Please don’t make this change.


On Sep 26, 2012, at 11:36 AM, Jay K <jay.krell at cornell.edu> wrote:It is not pervasive.It is like one line in about six files. M3CG.T => M3CG_Ops.Publics.

I guess you are saying that M3CG.T is merely the extremely abstract ROOT, where M3CG_Ops.Public has a bunch of methods? Then I might argue that M3CG.T is overly abstract -- it is like void* instead of pointer just with a bunch of methods.

This isn't quite right, doesn't compilte, but rougly:
Index: M3CG_BinRd.i3===================================================================RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_BinRd.i3,vretrieving revision 1.2diff -u -r1.2 M3CG_BinRd.i3--- M3CG_BinRd.i3	12 Feb 2001 15:25:47 -0000	1.2+++ M3CG_BinRd.i3	26 Sep 2012 15:34:32 -0000@@ -3,9 +3,9 @@  INTERFACE M3CG_BinRd; -IMPORT M3CG, Rd;+IMPORT M3CG_Ops, Rd; -PROCEDURE Inhale (rd: Rd.T;  cg: M3CG.T);+PROCEDURE Inhale (rd: Rd.T;  cg: M3CG_Ops.Public); (* Parse the binary intermediate code M3CG calls from 'rd'    and call 'cg' to implement them. *) Index: M3CG_BinRd.m3===================================================================RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_BinRd.m3,vretrieving revision 1.19diff -u -r1.19 M3CG_BinRd.m3--- M3CG_BinRd.m3	4 Sep 2012 14:29:54 -0000	1.19+++ M3CG_BinRd.m3	26 Sep 2012 15:34:32 -0000@@ -20,7 +20,7 @@ TYPE   State = RECORD     rd     : Rd.T;-    cg     : M3CG.T;+    cg     : M3CG_Ops.Public;     buf    : InputBuffer;     buf_len: CARDINAL;     buf_ptr: CARDINAL;@@ -200,7 +200,7 @@     Cmd {Bop.fetch_and_xor,  fetch_and_xor}   }; -PROCEDURE Inhale (rd: Rd.T;  cg: M3CG.T) =+PROCEDURE Inhale (rd: Rd.T;  cg: M3CG_Ops.Public) =   VAR s: State;  op: M3CG.Name;  cmd: INTEGER;   BEGIN     s.rd      := rd;Index: M3CG_BinWr.i3===================================================================RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_BinWr.i3,vretrieving revision 1.2diff -u -r1.2 M3CG_BinWr.i3--- M3CG_BinWr.i3	12 Feb 2001 15:25:47 -0000	1.2+++ M3CG_BinWr.i3	26 Sep 2012 15:34:32 -0000@@ -3,9 +3,9 @@  INTERFACE M3CG_BinWr; -IMPORT M3CG, Wr;+IMPORT M3CG_Ops, Wr; -PROCEDURE New (wr: Wr.T): M3CG.T;+PROCEDURE New (wr: Wr.T): M3CG_Ops.Public; (* returns a fresh, initialized code generator that writes its    calls as binary intermediate code on 'wr'.  See M3CG_Binary    for the binary format.  *)Index: M3CG_BinWr.m3===================================================================RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_BinWr.m3,vretrieving revision 1.23diff -u -r1.23 M3CG_BinWr.m3--- M3CG_BinWr.m3	4 Sep 2012 15:20:09 -0000	1.23+++ M3CG_BinWr.m3	26 Sep 2012 15:34:32 -0000@@ -27,7 +27,7 @@   END;  TYPE-  U = M3CG.T OBJECT+  U = M3CG_Ops.Public OBJECT         wr            : Wr.T := NIL;         buf           : M3Buf.T := NIL;         buf_len       : INTEGER := 0;@@ -375,7 +375,7 @@  (*---------------------------------------------------------------------------*) -PROCEDURE New (output: Wr.T): M3CG.T =+PROCEDURE New (output: Wr.T): M3CG_Ops.Public =   VAR mbuf := M3Buf.New ();   BEGIN     M3Buf.AttachDrain (mbuf, output);Index: M3CG_Check.i3===================================================================RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_Check.i3,vretrieving revision 1.1.1.1diff -u -r1.1.1.1 M3CG_Check.i3--- M3CG_Check.i3	14 Jan 2001 13:40:37 -0000	1.1.1.1+++ M3CG_Check.i3	26 Sep 2012 15:34:32 -0000@@ -7,11 +7,11 @@  INTERFACE M3CG_Check; -IMPORT M3CG;+IMPORT M3CG_Ops; -PROCEDURE New (child: M3CG.T;+PROCEDURE New (child: M3CG_Ops.Public;                clean_jumps, clean_stores: BOOLEAN;-               nested_calls, nested_procs: BOOLEAN): M3CG.T;+               nested_calls, nested_procs: BOOLEAN): M3CG_Ops.Public; (* returns a fresh, initialized code generator that passes its calls    to 'child' and checks that the stream obeys the M3CG restrictions.    If 'clean_jumps', it also checks that the stack is empty at everyIndex: M3CG_Check.m3===================================================================RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_Check.m3,vretrieving revision 1.17diff -u -r1.17 M3CG_Check.m3--- M3CG_Check.m3	4 Sep 2012 14:47:43 -0000	1.17+++ M3CG_Check.m3	26 Sep 2012 15:34:33 -0000@@ -32,7 +32,7 @@   };  TYPE-  U = M3CG.T OBJECT+  U = M3CG_Ops.Public OBJECT         clean_stores := FALSE;         clean_jumps  := FALSE;         nested_calls := TRUE;===================================================================RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_Ops.i3,vretrieving revision 1.12diff -u -r1.12 M3CG_Ops.i3--- M3CG_Ops.i3	16 Aug 2012 13:12:35 -0000	1.12+++ M3CG_Ops.i3	26 Sep 2012 15:34:33 -0000@@ -30,7 +30,7 @@   Public = OBJECT (*------------------------------------------------ READONLY configuration ---*) -child: M3CG.T := NIL;+child: Public := NIL; (* The default methods simply call the corresponding method in 'child',    hence a vanilla 'M3CG.T' can be used as a filter where you override    only the methods of interest. *)Index: M3CG_Rd.i3===================================================================RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_Rd.i3,vretrieving revision 1.1.1.1diff -u -r1.1.1.1 M3CG_Rd.i3--- M3CG_Rd.i3	14 Jan 2001 13:40:37 -0000	1.1.1.1+++ M3CG_Rd.i3	26 Sep 2012 15:34:33 -0000@@ -7,9 +7,9 @@  INTERFACE M3CG_Rd; -IMPORT M3CG, Rd;+IMPORT M3CG_Ops, Rd; -PROCEDURE Inhale (rd: Rd.T;  cg: M3CG.T);+PROCEDURE Inhale (rd: Rd.T;  cg: M3CG_Ops.Public); (* Parse the M3CG calls from 'rd' and call 'cg' to implement them. *)  END M3CG_Rd.Index: M3CG_Rd.m3===================================================================RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_Rd.m3,vretrieving revision 1.15diff -u -r1.15 M3CG_Rd.m3--- M3CG_Rd.m3	4 Sep 2012 14:52:46 -0000	1.15+++ M3CG_Rd.m3	26 Sep 2012 15:34:33 -0000@@ -22,7 +22,7 @@ TYPE   State = RECORD     rd     : Rd.T;-    cg     : M3CG.T;+    cg     : M3CG_Ops.Public;     ch     : CHAR;  (* current scan character *)     buf    : InputBuffer;     buf_len: CARDINAL;@@ -206,7 +206,7 @@   cmds: IntIntTbl.T := NIL;   types: IntIntTbl.T := NIL; -PROCEDURE Inhale (rd: Rd.T;  cg: M3CG.T) =+PROCEDURE Inhale (rd: Rd.T;  cg: M3CG_Ops.Public) =   VAR s: State;  op: M3CG.Name;  cmd: INTEGER;   BEGIN     s.rd      := rd;Index: M3CG_Wr.i3===================================================================RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_Wr.i3,vretrieving revision 1.1.1.1diff -u -r1.1.1.1 M3CG_Wr.i3--- M3CG_Wr.i3	14 Jan 2001 13:40:37 -0000	1.1.1.1+++ M3CG_Wr.i3	26 Sep 2012 15:34:33 -0000@@ -7,9 +7,9 @@  INTERFACE M3CG_Wr; -IMPORT M3CG, Wr;+IMPORT M3CG_Ops, Wr; -PROCEDURE New (wr: Wr.T): M3CG.T;+PROCEDURE New (wr: Wr.T): M3CG_Ops.Public; (* returns a fresh, initialized code generator that writes its    calls as readable ASCII on 'wr'. *) Index: M3CG_Wr.m3===================================================================RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_Wr.m3,vretrieving revision 1.18diff -u -r1.18 M3CG_Wr.m3--- M3CG_Wr.m3	22 Aug 2012 14:15:40 -0000	1.18+++ M3CG_Wr.m3	26 Sep 2012 15:34:33 -0000@@ -27,7 +27,7 @@   END;  TYPE-  U = M3CG.T OBJECT+  U = M3CG_Ops.Public OBJECT         wr            : Wr.T := NIL;         buf           : M3Buf.T := NIL;         buf_len       : INTEGER := 0;@@ -375,7 +375,7 @@  (*---------------------------------------------------------------------------*) -PROCEDURE New (output: Wr.T): M3CG.T =+PROCEDURE New (output: Wr.T): M3CG_Ops.Public =   VAR mbuf := M3Buf.New ();   BEGIN     M3Buf.AttachDrain (mbuf, output);Index: Target.i3===================================================================

 - Jay

From: hosking at cs.purdue.edu
Date: Wed, 26 Sep 2012 10:42:26 -0400
To: jay.krell at cornell.edu
CC: m3devel at elegosoft.com
Subject: Re: [M3devel] M3CG_Ops.Public vs. M3CG.T

I disagree.  M3CG.T is more abstract than M3CG_Ops.  The revelation of M3CG.T <: M3CG_Ops.Public is in M3CG_Ops.  If you want the ops you simply import that interface to get the revelation.  Please don’t make pervasive changes in interfaces that some of us are developing against.

On Sep 26, 2012, at 4:11 AM, Jay K <jay.krell at cornell.edu> wrote:M3CG_Ops.i3:

child: M3CG.T := NIL;(* The default methods simply call the corresponding method in 'child',   hence a vanilla 'M3CG.T' can be used as a filter where you override   only the methods of interest. *)
1)
I am not keen on fixing this, but I feel this was clearly a mistake.
M3CG_Ops.Public should have been "purely abstract" with no defaultimplementation.M3CG_Filter.T or somesuch could have been as described.

2) I am fixing:M3CG.T is overused.Most uses should be M3CG_Ops.Public.It is ok to derive from -- though that was a mistake.But functions that take or return M3CG.T should really betaking and returning M3CG_Ops.Public.

  - Jay

 		 	   		   		 	   		  
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://m3lists.elegosoft.com/pipermail/m3devel/attachments/20120927/b0ad5030/attachment-0002.html>


More information about the M3devel mailing list