[M3devel] small objects

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


Mika Nystrom wrote:
> Sigh, I hate sending so many emails to a mailing list.  Sorry about
> the inboxes I'm clogging of people with no interest in this.
>
> But I just realized something important, which I think may be
> decisive in deciding the fate of the name "REFANY" in the addition
> of new types.
>
> Rodney proposes 
>
> TAGGED T <: TAGGED REFANY
>   
No.  I am specifically proposing that TAGGED T and TAGGED U
have _no_ subtype relation, when T #U.   Putting the tagged
types into their own hierarchy creates a big complicated subtype
mess, with both two hierarchies on the one hand and subtype
cross-links between them on the other hand.  I also really calls
for a new, complex structural type equality rule that is very out
of sync with the existing type equality rule.

> T <: REFANY <: TAGGED REFANY
>
> I propose
>
> TAGGED T <: REFANY
> T <: UNTAGGEDREFANY <: REFANY
>
> Both proposals are identical in the power of the language that
> results, because they differ merely in naming.
>
> Both proposals are also backward-compatible: all existing Modula-3
> programs are unchanged by them.
>
> However, UNTAGGEDREFANY (mine), is *forward*-compatible as well
> as backward-compatible.
>
> Think about it.  The TAGGED REFANY proposal will have the following
> effect: people will go through all the M3 libraries and replace
> every or almost every occurrence of REFANY with TAGGED REFANY.  The
> resulting code will not compile with an older compiler!
>
> In my proposal, it is the user of the TAGGED types who is responsible
> for---in new code only!---deciding whether he wants his code to
> compile both on older and newer M3 systems.  If he does, then he
> can add appropriate implementations for compilers that don't support
> the TAGGED types (which will be trivial since he has to have those
> anyway!)  The burden of handling change is on the programmer of the
> special new feature rather than on everyone who has a container
> module.
>   
Well, I do see how this certain class of uses of REFANY could
have their meaning changed in this way, with no required
editing of source code.  But it reminds me of the joke that
real programmers don't fix their code, they just patch the
compiler. 

Despite my strong belief in the ability to have portable code, I
think it is a terrible thing to have the same code have fundamentally
different semantics when compiled by different compilers, even
if you can cite a large class of uses for which this semantic change
happens to be handy. 

For portable container data structures between pre/post tagged
Modula-3, declare a type in one place and change it in that one place:
TYPE MostGeneralContainerElement = REFANY.
or TYPE MostGeneralContainerElement = TAGGED REFANY.
Then have all the containter ADTs equate their element type to
this. 

It is also a glaring inconsistency to have all reference types other
than REFANY to be untagged by default and made tagged by an
explicit TAGGED, while REFANY defaults the other way around.
> I'll try to refrain from posting any more messages on this topic now.
>
>      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