[M3devel] M3CG_Ops.Public vs. M3CG.T

Rodney M. Bates rodney_bates at lcwb.coop
Tue Oct 16 18:36:35 CEST 2012


I'm finally getting around to responding to this.

On 09/27/2012 02:00 PM, Jay K wrote:> 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.

Modula-3's hiding mechanism, while a lot simpler to define, is *much*
more flexible than C++'s.  In fact, the flexibility is, in a sense,
unbounded.  The fields and methods of an object type can have a
different, arbitrary subset of them made visible in every interface or
module.  Just make a chain of opaque subtypes for each clump of
fields/methods whose visibility you want to be able to control
independently.  Then provide a revelation for each clump.

The one limitation is that each of the revelations has to be in a
separate interface, because you want to be able to import any subset
of the revelations, but you can't directly import a revelation, only
an interface, which brings in all the revelations in that interface.
This makes it syntactically a bit ponderous.  But this cost brings a
big benefit in language simplicity.  A few sentences of language
definition suffice, instead of a few pages.



 >
 >    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 METHODS
 > PROCEDURE F2();
 > END;
 >
 > Foo.m3:
 >    REVEAL Foo = OBJECT METHODS
 >    PROCEDURE F1();
 >    PROCEDURE F2();
 >    END;
 >

You can write something like this, but Foo1.Foo and Foo2.Foo are
distinct types not related to each other, nor to FooRoot.Foo.  All
three are side-by-side inheritance children of ROOT.  Also, Foo1.Foo
and Foo2.Foo will have to have full revelations somewhere.  I'm not
sure what you meant here, but I doubt this was it.

 >    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;
 >

Which is the same, apart from the nonexistence of Foo2 and Foo2.Foo.

 >
 >    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. ?
 >
 >

I think not requiring linearizing fields/methods would inevitably suck
you into the tar pit of multiple inheritance.  Multiple inheritance
has been debated to death many times.  The most charitable thing you
can say is the price in semantic complexity outweighs, by orders of
magnitude, the useful benefits.



Here is an example showing visibility of arbitrary subsets of 3 fields:

INTERFACE Opaque
; TYPE HideA <: ROOT
; TYPE HideB <: HideA
; TYPE HideC <: HideB
; TYPE T <: HideC
; END Opaque
.

INTERFACE ShowA
; IMPORT Opaque
; REVEAL Opaque . HideA = BRANDED OBJECT A : INTEGER := 1 END
; END ShowA
.

INTERFACE ShowB
; IMPORT Opaque
; REVEAL Opaque . HideB = Opaque . HideA BRANDED OBJECT B : INTEGER := 1 END
; END ShowB
.

INTERFACE ShowC
; IMPORT Opaque
; REVEAL Opaque . HideC = Opaque . HideB BRANDED OBJECT C : INTEGER := 1 END
; END ShowC
.

MODULE Opaque
; REVEAL T = HideC BRANDED OBJECT END
; BEGIN END Opaque
.

MODULE Client EXPORTS Main
; IMPORT Opaque
; IMPORT ShowA
; IMPORT ShowB
; IMPORT ShowC

; VAR O := NEW ( Opaque . T )

; BEGIN
     O . A := 4 (* Legal iff ShowA is imported. *)
   ; O . B := 5 (* Legal iff ShowB is imported. *)
   ; O . C := 6 (* Legal iff ShowC is imported. *)
   ; EVAL O
   END Client
.



 >   - Jay



More information about the M3devel mailing list