[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