[M3devel] small objects

Tony Hosking hosking at cs.purdue.edu
Tue Apr 7 04:16:29 CEST 2009


On 7 Apr 2009, at 10:42, Mika Nystrom wrote:

> You mean this proposal (you had two, I think)?

Yes, this is the proposal I converged on.  It really is only minimal  
change to the type system: introduction of a third hierarchy of   
TAGGED reference types.  I did something similar for orthogonal  
persistence a few years ago where it was useful to have a TRANSIENT  
reference hierarchy for things that should not persist.  [The  
semantics was that every run of a program would initialize TRANSIENT  
references to NIL rather than have them have the persistent value.   
This was slightly messier in that I also permitted TRANSIENT REFANY <:  
REFANY, which was a little odd.]

> --
>
> 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.
>
> ---
>
> I like it fine, I think... I'm just worried, generally, about
> changing the type system.  Hmmmm... you mean that the TAGGED
> things would just be a separate hierarchy?

The change is relatively minor in that it doesn't touch the original  
REFANY hierarchy.

> So you'd just add TAGGED in front of the REFs for this new hierarchy.
> But why no NULL?

No NULL because then we need a test for both NIL and values of type  
TAGGED INTEGER on every dereference.  You can easily declare:

TYPE Null = TAGGED INTEGER;
CONST Nil = VAL(0, TAGGED INTEGER);

The point is that TAGGED INTEGER now lets you have a range of non- 
pointer reference values, whereas NIL is the singleton non-reference  
value in type NULL.

> And you're comfortable with doing the conversions automatically?

No, I said that the conversions needed to be explicit

>
> So
>
>  tx : TAGGED INTEGER := 5;

tx: TAGGED INTEGER := VAL(5,TAGGED INTEGER);

>  x  : INTEGER := tx;

x: INTEGER := ORD(tx);

> would be OK?
>
> In that case it's just the m3tk that needs to be modified, and
> that's just busy work, I think.  If it works it's beautiful...

As I said, I am almost done with the compiler changes, and only need  
to push it into the run-time.  Things like m3tk and pickles will need  
to be smartened up as necessary.

>
>
>     Mika
>
>
>
> Tony Hosking writes:
>> I really don't like your proposal for the reasons you mention.  It
>> makes regular REF more expensive than it currently is.  What is it
>> about my relatively minor changes to the type system that you object
>> to?  I've just about finished changing the compiler front-end (in
>> relatively minor ways) to accomodate the proposal I made yesterday.
>> And it has the advantage of separating REF from TAGGED REF so we keep
>> the standard REF clean.
>>
>> On 7 Apr 2009, at 00:50, Mika Nystrom wrote:
>>
>>> Hi Rodney,
>>>
>>> I would like this capability too, but I am a bit wary of Tony's
>>> idea of changing the Modula-3 language---even in a "minor" way.
>>> I've been working for the last week or so on an application using
>>> the Modula-3 Toolkit, and I must say I have realized that the
>> Modula-3 type system has a lot more subtleties than I thought.  I
>>> would not want to make any real changes to it.  There's a paper
>>> called "The Modula-3 Type System" by Cardelli, Donahue, Kalsow, and
>>> Nelson that is worth studying in detail before making any changes
>>> whatsoever, I think.  Also remember that changes to the type system
>>> will affect m3tk and anything that depends on m3tk (which includes
>>> two or three stub generators in the main tree and who knows how
>>> many dependencies outside of it).
>>>
>>> I'm still not sure why we can't take the approach of Word.T .
>>> Make a RefanyOrInt.T that can safely be:
>>>
>>> 1. Tested whether it is a small integer or a REFANY
>>>
>>> 2. If a REFANY, be dereferenced as normal, *or* via
>>>  RefanyOrInt.ToRefany
>>>
>>> 3. If a small integer, can be extracted via RefanyOrInt.ToInt
>>>
>>> 4. Created either as a small integer or a REFANY
>>>
>>> Any other operations on it (including ISTYPE and TYPECASE, at least
>>> when the object is a small integer) would result in a checked  
>>> runtime
>>> error.
>>>
>>> Note that with the declaration "RefanyOrInt.T = REFANY", the current
>>> compiler will as far as I know not accept any operations on
>>> RefanyOrInt.T outside of ISTYPE, TYPECASE, and NARROW (explicit or
>>> implicit).
>>>
>>> I wouldn't be surprised if most of what I'm proposing already works
>>> (i.e., crashes with a checked runtime error as it should) with the
>>> current runtime.  Anything that slips through would need to be fixed
>>> up with a one-bit check of the LSB of the REFANY for the operations
>>> mentioned above.  Unfortunately this has to be done for operations  
>>> on
>>> every REFANY, not just the new type.
>>>
>>> I think that Modula-3 programmers are already aware that using
>>> REFANYs involves forcing the runtime to do extra type-checking work,
>>> so they already know not to use them if they are looking for maximum
>>> performance, so I don't think that burdening operations on REFANY
>>> with an extra one-bit check is too onerous.
>>>
>>> An advantage of my proposal is that the amount of code in the new
>>> proposed library is truly diminutive.  In fact, I think I posted
>>> pretty much that code to the list a few weeks ago.
>>>
>>> (If you missed it, it's
>>>
>>> http://www.async.caltech.edu/~mika/interp/
>>>
>>> )
>>>
>>>    Mika
>>>
>>>
>>> "Rodney M. Bates" writes:
>>>> I spent quite a bit of time playing with a more general system  
>>>> where
>>>> there is a set of "tagged" types, with (an implementation-defined
>>>> subrange of) INTEGER and a reference type both being a subtype of a
>>>> tagged type.  It might have been tolerable, if it weren't for the
>>>> interaction with object subtypes and opaque types, which quickly
>>>> gets deep into a deep linguistic tar pit.
>>>>
>>>> Tony's approach is much simpler and would serve what I see as the
>>>> need.  It does sacrifice any static checking of what reference type
>>>> is being tagged, and will also require an extra runtime ISTYPE/
>>>> TYPECASE.
>>>>
>>>> Would INTEGER and REFANY be assignable to TAGGED, or would there
>>>> also need to be an explicit conversion in that direction too, say
>>>> VAL(x, TAGGED)?  I think I favor the explicit conversion here.  It
>>>> is a bit inconsistent with the usual Modula-3 assignability
>>>> philosophy,
>>>> but not requiring the explicit conversion already gets your toes
>>>> into tar.
>>>>
>>>> We would have to have something more like ISTYPE, though, which  
>>>> will
>>>> tell which type the value belongs to without risking a runtime  
>>>> error,
>>>> which VAL would do.
>>>>
>>>> An intermediate approach might be to have a set of tagged types
>>>> constructed by, say, TAGGED T, where I is a reference type, but
>>>> with no subtype relations on them at all, thus still requiring
>>>> the explicit conversions and checks.
>>>>
>>>> I do want to say, I _really_ want this capability somehow.  I have
>>>> an ADT module whose internal data structure, for full generality,
>>>> needs to have two heap objects (the second because it has nonstatic
>>>> size) and 11 total words counting the orginal pointer, in the  
>>>> case of
>>>> values that would fit directly  into the "pointer" word.  Moreover,
>>>> these small cases are in the great majority.
>>>>
>>>> Besides the 11-to-one increase in actual occupied space, there
>>>> is extra time for allocation, periodic tracing, and collection,  
>>>> space
>>>> loss due to heap fragmentation, and time/space tradeoff loss due to
>>>> reduced locality of reference.  So sometimes, it would be a big
>>>> performance gain if we could do it.
>>>>
>>>>
>>>> Tony Hosking wrote:
>>>> It is a much more pervasive hack than I would be comfortable with
>>>>> since it touches on the compiler (for all the type operations) as
>>>>> well
>>>>> as the run-time system in ways that are pretty gross.  I would  
>>>>> much
>>>>> rather have a new TAGGED builtin.  ISTYPE would not work on it  
>>>>> since
>>>>> that only works on references.  The only thing you need is a way  
>>>>> to
>>>>> extract the value -- we could overload VAL(x, T) where x can be a
>>>>> TAGGED and T can be REFANY or INTEGER.
>>>>>
>>>>>




More information about the M3devel mailing list