From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,5606d8433901738c X-Google-Attributes: gid103376,public From: bobduff@world.std.com (Robert A Duff) Subject: Re: Allocating "initialized" limited types... Date: 1996/08/31 Message-ID: X-Deja-AN: 177689612 references: organization: The World Public Access UNIX, Brookline, MA newsgroups: comp.lang.ada Date: 1996-08-31T00:00:00+00:00 List-Id: In article , Jon S Anthony wrote: >What was the reasoning behind the 4.8(7) definition that an initialized >allocator boils down to an assignment? Any reason why this could not have >been defined as the creation of an instance with the fields as given by >the qualified expression? Well, it *is* a copy, and the whole point of limited types is to prevent copying. I don't see any difference between assignment and just copying all the fields over -- that's what assignment *does*. For example, suppose there is a limited private type implemented as an access type. The designer of that abstraction wanted to prevent having two such pointers pointing to the same thing, and so made it limited. Now, a client says: X: The_Limited_Type; type T is access The_Limited_Type; Y: Y := new The_Limited_Type'(X); -- Illegal. If this were legal, the client would have succeeded in making a copy of X, which is exactly what "limited" is supposed to prevent. Imagine a limited record type containing a component with an access discriminant that points to the outer record. Allowing a copy would destroy that access discriminant. Imagine copying a task -- it makes no sense in Ada 95. (I suppose it could have made sense in Ada 83, where a task value was not a task, but a pointer to a task. But in Ada 95, a task value is a task -- just like an integer value is an integer.) I don't see why allocators are special -- a copy is a copy. Ada 95 went to some trouble to patch some holes in Ada 83 where one could make copies of limited types, by the way. >Because of this, allocating limited types with given fields is not very >clean and in some cases requires superfluous conversions. Maybe someone >knows a clever way out of this? For example, suppose you have a limited >tagged type and an access type whose designated type is the tagged type's >class: > > type T is tagged limited private; > type T_Ref is access all T'Class; > >Utilizing T_Ref, you construct some general operations constructing >and manipulating hetergeneous lists of things in T'Class. At certain >places you will want to create these lists by adding to them things >in T'Class provided by allocators of the relevant child types. So, >you may have something like: > > type C is new T with private; -- Extends with new fields... >... > A_List : Car_Cdr_List_Where_Car_Is_T_Ref; > Obj_Ref : T_Ref; > > loop > ... >(1) Obj_Ref := new C'(....); -- ILLEGAL, assignment to limited type! It's not clear to me what you plan to put in the "....", since T and C are both private. >(2) A_List := Obj_Ref + A_List; > ... > end loop > >(*) Changing (1) to > > Obj_Ref := new C; > Obj_Ref.New_Field1 := ... -- ILLEGAL, No such field in this view! You can say C(Obj_Ref.all).New_Field1 := ... Not exactly pretty, but it works. Another useful trick is to make all the record fields into discriminants (possibly of access type). Then you can initialize them using a discriminant constraint, which does the full coverage check you want. >Doesn't help and is much more prone to errors (forget one of those fields???) Maybe you're really asking why limited types don't allow aggregates? The "don't forget fields" feature is a property of aggregates, not allocators. It's not clear how one could deal with access discrims in an aggregate. Maybe you could come up with some rules that allow aggregates in some cases, but only in initial values. Note that "X: T := expression;" is analogous to "new T'(expression);" -- both are initializers. The idea would be, I suppose, that the aggregate is built "in place", so there's no copy. You could also allow function_calls, where the function returns a local, if you're willing to have that local live outside the function (i.e. the local "becomes" the new object being initialized). I think Henry Baker once published a paper along those lines, but I don't have a reference (sorry). >IMO, this sucks, both because it requires a superfluous conversion and >because of the fact that it still requires error prone field by field >assignment. ... I'll grant you that Ada 95 has entirely too many superfluous conversions between access types. There are many other cases. The problem is that you normally want type-equivalence-by-structure for access types, whereas Ada always uses (essentially) type-equivalence-by-name. Access parameters are helpful, but that only works for parameters. - Bob