<html>
<head>
<style><!--
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
font-size: 12pt;
font-family:Calibri
}
--></style></head>
<body class='hmmessage'><div dir='ltr'> > If you allocate VAR V : Animal.T := NEW (Animal.T),   <br> > the result has allocated type Animal.T, not AnimalImpl.T. <br> > So it has no method private, and even with AnimalImpl  <br> > imported, trying to narrow it to AnimalImpl.T will <br> > suffer a runtime error.<br> <br> Sure, "creation is special" and "plain NEW doesn't necessarily<br> suffice".<br> <br> One would have<br>  INTERFACE Animal or AnimalImpl;   <br>  PROCEDURE Create(): Animal.T;  <br><br>  MODULE AnimalImpl;  <br>  <br>  PROCEDURE Create(): Animal.T =  <br>  BEGIN  <br>      RETURN NEW(AnimalTimpl.T);  <br>  END Create;  <br>    <br>    <br>  <br> >  I have noted that compilations sometimes tell us they are  <br> > recompiling some module because new opaque information has become available.  <br>   <br>   <br> Me too. And it appears this is an optional optimization.  <br> It initially compiles to something less efficient but correct.  <br> Then recompiles to something more efficient.  <br>    <br>   <br> > I'd just arrange to get the full, flat struct available anywhere it is needed  <br>   <br>   <br> If I can, then yes, agreed.  <br> I don't desire to hide information from the C compiler or debugger.  <br> In fact, there are related aspects of C++ that do hide too much from the  <br> debugger (e.g. COM -- all I can see in the debugger is the vtable  <br> and function pointers, instead of the debugger introspecting the most  <br> derived type and showing all the data members...)  <br>   <br>    <br>  >  I have never examined the way this is implemented. <br>    <br>  The generated C for my test case is surprising, very inefficient. <br>  In Main.m3 just to get the address of a.a involves like two <br>  lookups of static type data. <br><br>  <br>  <br>   What was the correction?  <br><br><br>  Thanks,   <br>   - Jay   <br> <br><br><br><br><br><div><div id="SkyDrivePlaceholder"></div>> Date: Sun, 31 Mar 2013 12:40:23 -0500<br>> From: rodney_bates@lcwb.coop<br>> To: m3devel@elegosoft.com<br>> Subject: Re: [M3devel] opaque types again --- A Correction<br>> <br>> <br>> <br>> On 03/31/2013 11:50 AM, Rodney M. Bates wrote:<br>> ><br>> ><br>> > On 03/31/2013 12:10 AM, Jay K wrote:<br>> >> I don't understand opaque types.<br>> >><br>> ><br>> > It can be tricky.<br>> ><br>> >><br>> >> I do understand the notion of fully opaque types. That are fully revealed in one step.<br>> >> In C this is common:<br>> >><br>> >><br>> >>    window.h<br>> >>      struct Window_t;<br>> >>      typedef struct Window_t Window_t;<br>> >>      Window_t* Window_Create();<br>> >>      void Window_Show(Window_*t);<br>> >>      void Window_Close(Window_*t);<br>> >>      long Window_GetHeight(Window_*t);<br>> >>      long Window_GetWidth(Window_*t);<br>> >>    etc.<br>> >><br>> >>    window.c<br>> >>      struct Window_t { ... } /* reveal */<br>> >><br>> >><br>> >> Back to Modula-3... opaque types must be OBJECTs, right?<br>> >><br>> ><br>> > It's slightly more liberal than that.  They can be any reference type, which<br>> > includes object types and REF Mumble, for any Mumble.  But since the subtype<br>> > hierarchy has only two levels for REF types (REFANY and REF Mumble), you can<br>> > only get fully opaque and fully revealed, as in the C example above.<br>> ><br>> >><br>> >> 1. What do they provide vs. more derived types?<br>> >><br>> >><br>> >> INTERFACE Animal;<br>> >><br>> >> TYPE T = OBJECT<br>> >> METHODS<br>> >>      makeNoise();<br>> >> END;<br>> >><br>> >><br>> >> INTERFACE AnimalImpl;<br>> >><br>> >> TYPE T = Animal.T OBJECT<br>> >> METHODS<br>> >>      private();<br>> >> END;<br>> >><br>> >><br>> >> If I had an Animal.T and wanted to call private(),<br>> >> wouldn't I just NARROW it to AnimalImpl.T?<br>> >><br>> ><br>> > If you allocate VAR V : Animal.T := NEW (Animal.T), the result has allocated type Animal.T, not AnimalImpl.T.<br>> > So it has no method private, and even with AnimalImpl imported, trying to narrow it to AnimalImpl.T will<br>> > suffer a runtime error.<br>> ><br>> > If you do it this way: VAR V : Animal.T := NEW (AnimalImpl.T), V still has static type Animal.T, but<br>> > its runtime value is (for now, at least) an object with allocated type AnimalImpl.T, which has method<br>> > private, and you can thus narrow it to AnimalImpl.T and call private.<br>> ><br>> >><br>> >> Is the point that it is more efficient and avoids<br>> >> a runtime type check?<br>> >><br>> ><br>> > That's part of it.<br>> ><br>> >><br>> >><br>> >> INTERFACE Animal;<br>> >><br>> >> TYPE Public = OBJECT<br>> >> METHODS<br>> >>      makeNoise();<br>> >> END;<br>> >><br>> >> TYPE T <: Public;<br>> >><br>> >> INTERFACE AnimalImpl;<br>> >><br>> >> REVEAL Animal.T = Animal.Public OBJECT<br>> >> METHODS<br>> >>      private();<br>> >> END;<br>> >><br>> >><br>> ><br>> > Here, even in a context where it is not revealed, if you allocate VAR V : Animal.T := NEW (Animal.T),<br>> > the allocated type has method private.  Note that Animal.T here is the same type as AnimalImpl.T is<br>> > in the first example.  You just don't know all there is to know about what type that is.<br>> ><br>> > So the object still sits in the heap with all the fields and methods of the final type.  If you<br>> > import AnimalImpl, this gives more (static) information about the same type Animal.T instead of just<br>> > a different type.  So the revelation would make it statically legal to call V.private(), without needing a<br>> > narrow and without a runtime check.  It is statically known everywhere Animal is imported, that<br>> > objects of Animal.T have all the properties of the final revealed type, even though it's not knowy what<br>> > they all are.<br>> ><br>> > Of course, you could also do this: VAR W : Animal.Public := NEW (Animal.Public), and that would<br>> > behave just like Animal.T of the first example, since those are the same type.  Usually, you would probably<br>> > not want to use Animal.Private in that way.  It's something like a variation on the theme of an abstract<br>>                    Animal.Public<br>> > supertype that you will never allocate.<br>> ><br>> > Sometimes I think it would help clarity if you could define a reference type as ABSTRACT, meaning it's<br>> > illegal to allocate it.  But that might open a can of worms in the language.  Hmm, maybe I'll work on<br>> > remembering to write (*ABSTRACT*) OBJECT ... I think I even did that once.<br>> ><br>> >> ?<br>> >> This way I can import AnimalImpl and then just call private()<br>> >> without a NARROW?<br>> >><br>> >><br>> ><br>> > Yes<br>> ><br>> >><br>> >><br>> >><br>> >> 2. Given that the final revelation must be a linear<br>> >> form of all the declared subtypes, I don't understand<br>> >> how the offset used by any module w/o a full revelation<br>> >> could be anything other than zero.<br>> >><br>> ><br>> > Not sure this helps much, but a complication comes from the fact that you can declare a truly new subtype<br>> > (not just reveal more about an existing opaque type), in a context where the opaque type is not fully revealed.<br>> ><br>> > IMPORT Animal (* The second version of Animal above. *)<br>> > TYPE Cat = Animal.T OBJECT<br>> >     IsDeclawed : BOOLEAN<br>> >     END;<br>> ><br>> > The compiler will not know while separately compiling this, the offset, relative to Animal.T, where new fields of<br>> > Cat will start.  I have never examined the way this is implemented.  I would think a typical linker's relocation<br>> > or external symbol mechanism could be used to add to the offset, a component that is defined in another compilation.<br>> > I think Tony understands how this is implemented.  I have noted that compilations sometimes tell us they are<br>> > recompiling some module because new opaque information has become available.<br>> ><br>> >><br>> >> I'd like to fully understand this, so I can make the C backend<br>> >> provide maximal type information. More pointers to structs, with members/fields,<br>> >> fewer untyped void*/char*.<br>> >><br>> ><br>> > If you are hoping to express Modula-3's actual static information hiding in C, I suspect that is a Quixotic quest.<br>> > At the very least, you would have to replace what is really a flat struct with lots of nesting of structs for<br>> > the different static visibility groups, which would just hurt readability elsewhere, in references to fields.<br>> > By definition, it is a lower-level form of code here.  I'd just arrange to get the full, flat struct available<br>> > anywhere it is needed, and rely on the fact that the M3 front end will already have refused to pass down any<br>> > references to fields that aren't statically legal in the M3 source code.  There is certainly no need to get<br>> > the C compiler to redundantly enforce this.<br>> ><br>> >><br>> >> Thanks,<br>> >>   - Jay<br>> >><br>> >><br>> ><br>> ><br>> <br></div>                                       </div></body>
</html>