[M3devel] small objects
Rodney M. Bates
rodney.m.bates at cox.net
Fri Apr 10 00:13:52 CEST 2009
Mika Nystrom wrote:
> hendrik at topoi.pooq.com writes:
>
>> On Thu, Apr 09, 2009 at 07:10:44AM -0700, Mika Nystrom wrote:
>>
>>> I don't know why we're having such a tough time understanding each
>>> other here :-)
>>>
>>> I think that what Rodney says is that he wants (in pseudo-modula-2
>>> syntax):
>>>
>>> T = CASE LSB OF
>>> 1 : SmallInt
>>> |
>>> 0 : U
>>> END;
>>>
>>> SmallInt = [SmallMin..SmallMax];
>>>
>>> for any reference type U.
>>>
>> Yes. That's what I wanted too, originally. I can accept the
>> restriction that the reference type U might be restricted to be
>> REFANY.
>>
>
> I think this is what Tony says he's implemented, essentially...
>
> ...
>
>>> The only problem I have with this (except for the changes necessary
>>> to Modula-3) is that it can't be held in a REFANY, and that's part
>>> of the design.
>>>
>> Much better not to pervert REFANY, but use a new type instead.
>>
>
> 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
and copying of the values would all work as before, and the client's passing
to TAGGED REFANY and later narrowing it to whatever reference type it put in
would also work as before, using the extended semantics of assignments
and narrowing operations.
>
>>> Of course we could go halfway and let it be held in a REFANY, but
>>> then you get the runtime LSB check again, for all instances of
>>> REFANY,
>>>
>> I really don't like requiriny a run-time check on REFANY. That's why
>> I want it to be a separate type.
>>
>
> All the operations in question already require (*much* more
> complicated) run-time checks on REFANY.... and most uses of REFANY
> still wouldn't require the LSB check.
>
> I really think the runtime issue is a non-issue, and as I said
> above, if it turns out to be a real issue, one can either abandon
> the change (since the whole thing can be implemented transparently
> with a library) or else re-root ROOT and all the REF types in a new
> NOTQUITEREFANY type. This would be a backward-compatible change
> (in every sense) with Tony's runtime changes:
>
> REFANY ; (* Tony's, with the LSB trick *)
>
> NOTQUITEREFANY <: REFANY;
>
> ROOT <: NOTQUITEREFANY;
>
> REF T <: NOTQUITEREFANY; (* for all T *)
>
> After that, future, change, people who want to avoid the LSB check
> on REFANY can instead use NOTQUITEREFANY. I think barely anyone
> will bother.
>
> Come to think of it, Modula-3 doesn't specify that there's no
> intermediate type between REFANY and ROOT and the other REF T's,
> so there's no way it could break the current language. In
> fact you don't have to "reveal" this new type in the language
> specification at all. It could just be a library type
> NotQuiteRefany.T.
>
> You could then introduce separately, a la Rodney,
>
> TAGGED T <: REFANY; (* for all T *)
>
> (* but *not* TAGGED T <: NOTQUITEREFANY *)
>
>
>
>>> but maybe it doesn't break anything else. Although you do
>>> in any case get LSB checks all over the place (in safe code!) where
>>> the TAGGED U is revealed to be a TAGGED U.
>>>
>>> Note that, as we probably all know, the Modula-3 designers expressly
>>> considered, and rejected, full variant records.
>>>
>> Are these the factors they based their decision on?
>>
>> (1) The ones in Pascal are insecure without a lot of run-time checking.
>>
>> (2) Objects and inheritance take care of much of the functionality.
>>
>> (3) The ones in Algol 68 involve copying entire records when
>> construction and deconstructing unions of records.
>>
>
> (1) and (2) at least. I'll quote:
>
> "[talk about runtime errors due to freeing still-used references]
>
> Another well-known runtime error is to assign to the tag of a variant
> record in a way that subverts the type system. Distinguishing
> subversive assignments from benign assignments in the language
> definition is error-prone and arbitrary. The objects and classes
> first introduced in Simula and adopted in Oberon and Object Pascal
> are more general than variant records, and they are safe, so we
> have discarded variant records and adopted objects.
>
> [talk about objects]"
>
> (See Cardelli et al., "The Modula-3 Type System" (c) 1989 ACM.)
>
> Mika
>
>
>> What we're considering not is the case in which (2) provides
>> excessive indirection and garbage-collector load, and in which
>> the copying in (3) is really cheap. There are applications
>> for which this feature could have major effects on efficiency.
>> I have some I'd consider rewriting from C/C++ to Modula 3
>> if this feature were available.
>>
>> -- hendrik
>>
> ....
>
>
More information about the M3devel
mailing list