[M3devel] M3CG_Ops.Public vs. M3CG.T

Coleburn, Randy rcolebur at SCIRES.COM
Thu Sep 27 21:48:14 CEST 2012


Jay:

Note that Modula-3 also has partial revelation.

(BTW, I like the design tenants of Modula-3.  I believe in them and have been successful using them.  This is a Modula-3 forum.  I know you seem to like C++, but I grow weary of the barrage of C/C++ from you.  I would like to see less criticism of Modula-3 and more of how we are going to keep the CM3 implementation evolving toward the best implementation of the language specification possible on a wide array of modern platforms.  If there is a perceived need for a language change, a specific proposal should be presented and vetted as a separate thread of discussion.  My 2 cents.)

--Randy Coleburn


From: jayk123 at hotmail.com [mailto:jayk123 at hotmail.com] On Behalf Of Jay K
Sent: Thursday, September 27, 2012 1:14 AM
To: Tony
Cc: m3devel
Subject: EXT: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 of
interface 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, but
they both map to Modula-3.


One form is a fully opaque type and a bunch of functions
that 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, no
data, 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 call
any methods/member-functions, but I don't see that hiding
them 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 is
mostly inferior. void* at least allows for basically the same implementation
strategies, including casting it to int and indexing into a table, but
having different pointer types allows for a little bit of type-safety
in the clients (i.e. avoiding passing a Windows_t* to File_Read).



 - Jay



________________________________
From: hosking at cs.purdue.edu<mailto:hosking at cs.purdue.edu>
Date: Wed, 26 Sep 2012 15:53:26 -0400
To: jay.krell at cornell.edu<mailto:jay.krell at cornell.edu>
CC: m3devel at elegosoft.com<mailto: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<mailto: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<mailto: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<mailto: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,v
retrieving revision 1.2
diff -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,v
retrieving revision 1.19
diff -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,v
retrieving revision 1.2
diff -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,v
retrieving revision 1.23
diff -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,v
retrieving revision 1.1.1.1
diff -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 every
Index: M3CG_Check.m3
===================================================================
RCS file: /usr/cvs/cm3/m3-sys/m3middle/src/M3CG_Check.m3,v
retrieving revision 1.17
diff -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,v
retrieving revision 1.12
diff -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,v
retrieving revision 1.1.1.1
diff -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,v
retrieving revision 1.15
diff -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,v
retrieving revision 1.1.1.1
diff -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,v
retrieving revision 1.18
diff -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<mailto:hosking at cs.purdue.edu>
Date: Wed, 26 Sep 2012 10:42:26 -0400
To: jay.krell at cornell.edu<mailto:jay.krell at cornell.edu>
CC: m3devel at elegosoft.com<mailto: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<mailto: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 default
implementation.
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 be
taking and returning M3CG_Ops.Public.


  - Jay


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


More information about the M3devel mailing list