[M3devel] opaque types again --- A Correction

Jay K jay.krell at cornell.edu
Sun Mar 31 21:54:28 CEST 2013


 > If you allocate VAR V : Animal.T := NEW (Animal.T),   
 > the result has allocated type Animal.T, not AnimalImpl.T. 
 > So it has no method private, and even with AnimalImpl  
 > imported, trying to narrow it to AnimalImpl.T will 
 > suffer a runtime error.
 
 Sure, "creation is special" and "plain NEW doesn't necessarily
 suffice".
 
 One would have
  INTERFACE Animal or AnimalImpl;   
  PROCEDURE Create(): Animal.T;  

  MODULE AnimalImpl;  
  
  PROCEDURE Create(): Animal.T =  
  BEGIN  
      RETURN NEW(AnimalTimpl.T);  
  END Create;  
    
    
  
 >  I have noted that compilations sometimes tell us they are  
 > recompiling some module because new opaque information has become available.  
   
   
 Me too. And it appears this is an optional optimization.  
 It initially compiles to something less efficient but correct.  
 Then recompiles to something more efficient.  
    
   
 > I'd just arrange to get the full, flat struct available anywhere it is needed  
   
   
 If I can, then yes, agreed.  
 I don't desire to hide information from the C compiler or debugger.  
 In fact, there are related aspects of C++ that do hide too much from the  
 debugger (e.g. COM -- all I can see in the debugger is the vtable  
 and function pointers, instead of the debugger introspecting the most  
 derived type and showing all the data members...)  
   
    
  >  I have never examined the way this is implemented. 
    
  The generated C for my test case is surprising, very inefficient. 
  In Main.m3 just to get the address of a.a involves like two 
  lookups of static type data. 

  
  
   What was the correction?  


  Thanks,   
   - Jay   
 




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


More information about the M3devel mailing list