[M3devel] small objects

Rodney M. Bates rodney.m.bates at cox.net
Mon Apr 13 04:12:29 CEST 2009


Mika Nystrom wrote:
> Specific proposal.
>
> What Rodney said, *except* make REFANY the root of everything.
> Insert an untagged root with a new name.
>
> Rodney himself has said that the uses of REFANY he knows about would
> be changed to accept the TAGGED type, 
No, not all of them.  Just those that are the element type of
general-purpose container data types. 

> so I simply propose allowing
> REFANY to handle the TAGGED type by default, and insert a new root
> for the untagged types.  The structure of the type hierarchy is
> exactly the same as in Rodney's proposal, but the different naming
> makes it more backward-compatible.
>
> ROOT <: UNTAGGEDREFANY
> T <: UNTAGGEDREFANY
>
> UNTAGGEDREFANY <: REFANY
>
> and finally.
>
> TAGGED T <: REFANY (* for all T *)
>
> The advantages with this proposal are that it does precisely what
> Rodney is asking for (typesafe ADTs), but it's compatible with 
> Tony's runtime changes in the *current* M3 implementation and it
> won't require anyone to do a massive search and replace, replacing
> REFANY with "TAGGED REFANY" in every existing Modula-3 program.
>
> Supposed disadvantage: every TYPECASE, NARROW, etc., of REFANY will
> cost an extra LSB check.  Those who feel strongly about that and
> for some reason *know* that they don't want to process TAGGED types
> (which may be the empty set), can modify their code to use
> UNTAGGEDREFANY instead of REFANY.
>   
I am still not sure we are communicating.  I am proposing
that _only_ the tagged types, i.e., those constructed by
TAGGED T, for T a traced or object type, can have a LSB
nonzero.  So TYPECASE and friends will not have an LSB
check when applied to T, only when applied to TAGGED T.
>      Mika
>
> "Rodney M. Bates" writes:
>   
>> Mika Nystrom wrote:
>>     
>>> Sorry to splice together two emails from you, but I feel I've already
>>> used up my m3devel quota this week:
>>>
>>> "Rodney M. Bates" writes:
>>>   
>>>       
>>>>> Are you sure?  I want a type---some type---that can hold "any
>>>>> reference, even a tagged one", and I would rewrite most library
>>>>> code that today takes REFANY to take that instead.  Why not?  Why
>>>>> would I want to limit it to REFANY when it performs no operations
>>>>> that couldn't legally be performed on TAGGED REFANY.
>>>>>
>>>>>       
>>>>>           
>>>> I believe my "safe" proposal would make this very simple, if I am
>>>> thinking of the kind of library code you are.
>>>>  
>>>> I envision a container data structure that takes in things and returns
>>>> them without performing operations on them other than moving them around
>>>> and storing them, e.g. the ever belabored stack.   The values going in
>>>> and out are declared REFANY, and the client passes in values of
>>>> some proper subtype of REFANY, which get assigned to the REFANY
>>>> parameters.   When it gets them back, it narrows them to this type.   
>>>>
>>>> In this pattern, just changing the declared type of the container values
>>>>     
>>>>         
>>> >from REFANY to TAGGED REFANY would do it.  The library code's storage
>>> ...
>>>   
>>>       
>> There are two very different kinds of uses of reference and
>> tagged types.  The one I speak of above is for the type of the
>> elements inside a container data structure.  In this case, it
>> is the client that knows what type the value really is, and will
>> declare it as such.  The library ADT module should know as little
>> as possible about it, so it will declare it as REFANY or
>> TAGGED REFANY.   Here, you want the  most general type
>> possible,  just to make the abstraction more versatile.  
>> And TAGGED REFANY  generalizes it from  REFANY.  
>>
>> But...
>>     
>>>   
>>>       
>>     
>>>>> you'd like to store these in a REFANY and dynamically test for the 
>>>>> appropriate tagged type:
>>>>>       
>>>>>           
>>>> No, I do not want to store these in a variable of type REFANY or any 
>>>> other existing type. 
>>>> In fact, I want to forbid it.
>>>>     
>>>>         
>>> I think you are thinking of exactly the same kind of library code.
>>> TextRefTbl.T, RefList.T, etc.
>>>
>>> After the introduction of TAGGED REFANY, what use is there for
>>> REFANY?  What piece of code can you think of where the cost of the
>>> 1-LSB check of TAGGED REFANY outweighs the convenience of being
>>> able to process objects of type TAGGED T (for all ref types T) as
>>> well as objects of type T?
>>>   
>>>       
>> The other use is for the abstract type itself.  Forgetting tagged
>> types for a moment, I have never seen an interface/module that
>> uses REFANY for this.   Instead, the modules declare their abstract
>> type as some proper subtype of REFANY, usually an opaque type.
>>
>> It would be possible to use just REFANY here of course, but that would
>> require an otherwise unnecessary RT check on the allocated type,
>> every time an operation of the module is called.  This is a much
>> more expensive check than a tag check, as has been pointed out
>> in this discussion.  
>>
>> But worse, it would sacrifice the static checking that we now have
>> that prevents, at compile time, clients  from passing, say a Text.T
>> to some procedure in Atom that expects an Atom.T.  If these modules
>> ever wanted to use a tagged type, but the only tagged type were
>> REFANY, we would lose this static checking, because Text.T would
>> have to become equal to Atom.T.
>>
>> In cases where your algorithms don't specifically need dynamic
>> typing, static typing is always much better, because one run of
>> the compiler on the source code will do it.  Bugs checked
>> only at runtime require a massive test suit to be coded and then
>> regularly rerun to get even close to the same confidence they've
>> been found.
>>
>> So when using tagged types as the ADT itself,, we need to be able
>> to have a tagged version of whatever proper subtype of REFANY
>> the abstraction needs, including an opaque subtype of REFANY
>> or an opaque subtype of some Public subtype of REFANY.  This is
>> why I am adamant that we need to be able to build a tagged type
>>     
> >from any traced or object type. 
>   
>> And once you do this, keeping REFANY itself unchanged and allowing
>> TAGGED REFANY as one case of a tagged type falls out of the system
>> for free _and_ saves a lot of cases that would otherwise need a new RT
>> check that can never fail, but the language can't know that, because
>> the type system has lost the distinction.
>>
>> I really feel that the fad of all dynamic typing in languages is a huge
>> mistake and that it will someday be recognized as such.  In the
>> meantime, we have a language that provides a very extensive set
>> of statically-typed alternatives, while also allowing dynamic typing
>> when you really need it.  This is one of Modula-3's best principles. 
>> Let's don't erode the static alternatives unnecessarily.
>>
>>     
>>>     Mika
>>>
>>>   
>>>       
>
>   




More information about the M3devel mailing list