[M3devel] small objects

Mika Nystrom mika at async.caltech.edu
Tue Apr 7 20:33:05 CEST 2009


So following my previous email, I suggest the following, which
doesn't change the language definition at all:

INTERFACE TaggedInteger;
IMPORT Word;

TYPE T <: REFANY;
     V = [ TaggedMin .. TaggedMax ];

CONST TaggedMin = -Word.Shift(1,BITSIZE(REFANY)-2); 
      TaggedMax =  Word.Shift(1,BITSIZE(REFANY)-2) - 1;

PROCECURE Extract(t : T) : V;

PROCEDURE New(v : V) : T;

(* ...the usual generic support routines... *)

END TaggedInteger.

The compiler, runtime, and the implementation of this interface
would be responsible for hiding the values in REFANYs, doing the
correct thing for NARROW, ISTYPE, TYPECASE, TYPECODE, # and =...

What functionality is missing?  I think the compiler/runtime changes
are pretty much the same no matter which of the proposals you go
with...

     Mika

"Rodney M. Bates" writes:
>Tagged types and object type hierarchies:
>
>At first, I was imagining that you could create
>an object subtype of a TAGGED type:
>
>(* An untagged hierarchy: *)
>TYPE O1 = OBJECT F1: INTEGER END;
>TYPE O2 = O1 OBJECT F2: CHAR END;
>TYPE O3 = O2 OBJECT F3: BOOLEAN END:
>
>(* Tag each one directly: *)
>TYPE TO1 = TAGGED O1;
>TYPE TO2 = TAGGED O2;
>TYPE TO3 = TAGGED O3;
>
>(* A tagged hierarchy: *)
>TYPE TO2S = TO1 OBJECT F2: CHAR END;
>TYPE TO3S = TO2S OBJECT F3: BOOLEAN END;
>
>Is TO2S = TO2 and TO3S = TO3?
>
>Is O2 <: TO2S and O3 <: TO3S?
>
>Therein lies tar.  The type equality and subtype relations are getting
>awfully elaborate for a language that advertises relative simplicity.
>
>Then I thought about two parallel hierarchies, one tagged and one not,
>as Tony's second proposal.  But that leaves it awfully inconvenient
>to have both a tagged and untagged counterpart that are otherwise the
>same, and you need the untagged counterpart to do ISTYPE/NARROW/TYPECASE/:=
>to get the "definitely-a-heap-reference" value out of a tagged type.
>
>If I read it right, Tony's first proposal does not allow to subclass an
>already tagged type  (i.e., no "tagged hierarchy" as above).  Is that
>what you meant, Tony?  If so, I think this is enough, and avoids the
>complicated type equality and subtype relations.
>
>A separate issue:
>
>On the INTEGER side of this, I think we need a builtin type that is an
>implementation-defined subrange of INTEGER, that can hold just the
>integer values a tagged type can hold.  Maybe "TAG"?  (Actually, this
>name is a poor choice, since it's not the tag itself, but it's the best
>I can think right now, so I will use it in discussion). 
>
>If we really want to constrain the implementation to always use exactly
>the low bit as the tag, then CARDINAL would do for this.  A new builtin
>type would leave open other tagging representations with other ranges of
>representable integers, as well as the low-bit tag with signed integers.
>
>Then we could also allow ISTYPE(x, TAG), etc. to get the "definitely-an-
>integer" value out.
>
>This gives fully type-safe support for small objects, which I really
>prefer, if not too complicated. 
>
>  
>
>Tony Hosking wrote:
>> I like the notion of having a TAGGED INTEGER type that is a hybrid 
>> ordinal/reference.
>>
>> Subtyping rules for references would now be as follows:
>>
>> NULL <: REF T <: REFANY
>> TAGGED INTEGER <: REF T <: REFANY
>>
>> ROOT <: REFANY
>> NULL <: T OBJECT ... END <: T
>> TAGGED INTEGER <: T OBJECT ... END <: T (but only for T <: REFANY, not 
>> T <: ADDRESS)
>>
>> Thus, TAGGED INTEGER is a funny sort of hybrid ordinal/reference 
>> type.  Values of TAGGED INTEGER are non-pointer values similar to the 
>> value NIL.  We can then do ISTYPE(x, TAGGED INTEGER), and NARROW(x, 
>> TAGGED INTEGER), and TYPECODE(TAGGED INTEGER), similarly to ISTYPE(x, 
>> NULL), NARROW(x, NULL), and TYPECODE(NULL).
>>
>> Because TAGGED INTEGER is an ordinal we can extract the integer value 
>> it holds using ORD(x).
>> Similarly, we can construct a TAGGED INTEGER using VAL(x, TAGGED 
>> INTEGER).
>>
>> ***The only problem with this scheme is how to efficiently perform 
>> run-time tests for dereferencing NULL, and TAGGED INTEGER?***
>>
>> So, here is a slightly less elegant alternative that is probably 
>> straightforward to implement.  Introduce a separate TAGGED hierarchy.
>>
>> NULL <: REF T <: REFANY
>> NULL <: UNTRACED REF T <: ADDRESS
>> TAGGED INTEGER <: TAGGED REF T <: TAGGED REFANY
>>
>> Note that NULL is not a subtype of TAGGED REF T or TAGGED REFANY.
>>
>> ROOT <: REFANY
>> TAGGED ROOT <: TAGGED REFANY
>> NULL <: T OBJECT END <: T where T <: REFANY or T <: ADDRESS
>> TAGGED INTEGER <: T OBJECT ... END <: T where T <: TAGGED REFANY
>>
>> Note that NULL is not a subtype of T OBJECT ... END where T <: TAGGED 
>> REFANY.
>>
>> This way, tagged references only need a run-time test for the tag on 
>> dereference (we can throw an "attempt to dereference TAGGED INTEGER" 
>> at run time, just like we throw "attempt to dereference NIL" for 
>> untagged references).  This check can be a straightforward test of the 
>> low bit tag.  Of course, the weird thing here is now that we don't 
>> have a single NULL value for TAGGED references --- we have multiple 
>> null values VAL(x, TAGGED INTEGER).  Instead of asking "x == NIL" we 
>> must ask "ISTYPE(x, TAGGED INTEGER)".
>>
>> Of course, because TAGGED INTEGER is an ordinal, we can also perform 
>> the usual ordinal operations like INC(x), DEC(x), wherever x is typed 
>> TAGGED INTEGER.
>>



More information about the M3devel mailing list