comp.lang.ada
 help / color / mirror / Atom feed
* Allocating "initialized" limited types...
@ 1996-08-30  0:00 Jon S Anthony
  1996-08-31  0:00 ` Robert A Duff
  0 siblings, 1 reply; 13+ messages in thread
From: Jon S Anthony @ 1996-08-30  0:00 UTC (permalink / raw)




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?

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!
        ...
(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!
        Obj_Ref.New_Field2 := ... -- ILLEGAL, No such field in this view!
        ...

Doesn't help and is much more prone to errors (forget one of those fields???)
anyway.  So, AFAICT, you need to do the following hack (and it is definitely
a hack...):

Change Obj_Ref's type:

    type C_Ref is access C'Class;  -- or maybe just C...
    Obj_Ref : C_Ref;

Proceed as in (*), which is now legal and change (2) to:

        A_List := T_Ref(Obj_Ref) + A_List;

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.  Sure, you can isolate this, but that really doesn't
change the fact...  There are a couple other hacks, but they seem even
worse.
-- 
Jon Anthony
Organon Motives, Inc.
1 Williston Road, Suite 4
Belmont, MA 02178

617.484.3383
jsa@organon.com





^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-08-30  0:00 Allocating "initialized" limited types Jon S Anthony
@ 1996-08-31  0:00 ` Robert A Duff
  1996-09-02  0:00   ` Jon S Anthony
                     ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Robert A Duff @ 1996-08-31  0:00 UTC (permalink / raw)



In article <JSA.96Aug30173704@alexandria>,
Jon S Anthony <jsa@alexandria> 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




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-08-31  0:00 ` Robert A Duff
  1996-09-02  0:00   ` Jon S Anthony
@ 1996-09-02  0:00   ` Jon S Anthony
  1996-09-03  0:00     ` Robert A Duff
  1996-09-06  0:00     ` Jon S Anthony
  1996-09-04  0:00   ` Jon S Anthony
  1996-09-05  0:00   ` Jon S Anthony
  3 siblings, 2 replies; 13+ messages in thread
From: Jon S Anthony @ 1996-09-02  0:00 UTC (permalink / raw)



In article <Dx0q2E.2Bw@world.std.com> bobduff@world.std.com (Robert A Duff) writes:

> In article <JSA.96Aug30173704@alexandria>,
> Jon S Anthony <jsa@alexandria> 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*.

Well, it *is* a copy if that's how you define it.  You don't have to
so define it in the user model.  And sure, copying all the field over
is basically assignment anyway.


> 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.

Yes, yes, of course.  That's actually why I'm using it for crying out
loud.  But in the _body_ of where the thing is defined this is just
irrelevant as you can copy the fields of X one at time and make your
copy any way.  This too, is part of the point.

Hmmm, actually there is another point poking through here: What I had
in mind was an aggregate where all the fields are specified (as non
copies) - not the sort of case where you use an _object_ of the type
for the aggregate.  Actually, I didn't even know you could do this -
thought that was a simple qualified expression (then again, I guess
that's what an aggregate is...).


[more obvious stuff deleted...]

> I don't see why allocators are special -- a copy is a copy.

Fine.  If that is the reasoning that went into it.  My claim is that
in the user model it does not have to be 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.

Yes, and that was a "good thing".


> >    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.

Not to the _BODY_.  So, it is TRIVIAL to put _NON COPY THINGS_ in the
'(...)  Actually, this is probably more to the point.  If you could
have had public limited views of _tagged_ types with their private
views being _NON_limited, this would solve the problem nicely.  So, I
guess the question should have been why was this disallowed.
Actually, I seem to recall a reason for this, but can't recall what it
was (seemed to make sense at the time...)


> >(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.

Yes, but I think my hack is nicer than this one...


> 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.

Yes, I've done this one too - it is _very_ useful, but not in those
cases where the discriminants are to be hidden.  So, this one didn't
work for me in the case at hand.  But this _is_ a nice way to go if it
fits.


> >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.

No, I really think what I was after is the above bit about limited
public and non limited private views of tagged types.  To me, not
allowing an aggregate is obvious: it is an assignment to the object
(not to its separate fields!) and thus illegal for limited types.


> Maybe you could come up with some rules that allow aggregates in some
> cases, but only in initial values.

Yes, that would work too.  But you're correct that is a kind of special
case hack.  Still...


>  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.

Yup, that is precisely the idea that I had in mind by the notion that
you would not have to define an initialized allocator as a copying
operation.  You have nailed down what I really had in mind.  The
reason allocators _seem_ special here, is that there is no object in
the _user model_ that is being assigned!

X : T := expression; -- Clearly an assignment IN THE USER MODEL to a T object

X : T_Ref := new T'(...); -- NOT an assignment to a T object
                          -- IN THE USER MODEL.  In the user model
                          -- a T_Ref object is being assigned!  Sure,
                          -- in the nefarious innards of the language
                          -- model this too has an assignment to a T
                          -- object - as currently defined.


> 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).

I'll take a look at his jumbo web site for his papers...


> 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.

Not when you are using access to class wide types.  That is more or
less the whole point of such things.  One named type representing
whole sets of possible structures.  Criminey, that's the whole point!

/Jon
-- 
Jon Anthony
Organon Motives, Inc.
1 Williston Road, Suite 4
Belmont, MA 02178

617.484.3383
jsa@organon.com





^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-08-31  0:00 ` Robert A Duff
@ 1996-09-02  0:00   ` Jon S Anthony
  1996-09-04  0:00     ` Joel VanLaven
  1996-09-06  0:00     ` Jon S Anthony
  1996-09-02  0:00   ` Jon S Anthony
                     ` (2 subsequent siblings)
  3 siblings, 2 replies; 13+ messages in thread
From: Jon S Anthony @ 1996-09-02  0:00 UTC (permalink / raw)



In article <JSA.96Sep1205656@alexandria> jsa@alexandria (Jon S Anthony) writes:

> In article <Dx0q2E.2Bw@world.std.com> bobduff@world.std.com (Robert A Duff) writes:
> 
> > In article <JSA.96Aug30173704@alexandria>,
> > Jon S Anthony <jsa@alexandria> wrote:
[...]
> > >    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.
> 
> Not to the _BODY_.  So, it is TRIVIAL to put _NON COPY THINGS_ in the
> '(...)  Actually, this is probably more to the point.  If you could
> have had public limited views of _tagged_ types with their private
> views being _NON_limited, this would solve the problem nicely.  So, I
> guess the question should have been why was this disallowed.
> Actually, I seem to recall a reason for this, but can't recall what it
> was (seemed to make sense at the time...)

OK, went back and checked this and it definitely makes sense to
disallow public limited tagged types from being completed as
non-limited tagged types.  If this were allowed, it would be possible
to violate limited semantics on public type extensions involving
limited components.  So, this clearly makes sense the way it is
(disallowed).


> > >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.
> 
> No, I really think what I was after is the above bit about limited
> public and non limited private views of tagged types.  To me, not
> allowing an aggregate is obvious: it is an assignment to the object
> (not to its separate fields!) and thus illegal for limited types.

Well, here I'm just in the weeds, having become side tracked by the
public/private limited/non-limited tagged type issue.  This really has
nothing to do with what I had in mind, which is really captured by the
notion of "in place" creation.


/Jon
-- 
Jon Anthony
Organon Motives, Inc.
1 Williston Road, Suite 4
Belmont, MA 02178

617.484.3383
jsa@organon.com





^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-09-02  0:00   ` Jon S Anthony
@ 1996-09-03  0:00     ` Robert A Duff
  1996-09-06  0:00     ` Jon S Anthony
  1 sibling, 0 replies; 13+ messages in thread
From: Robert A Duff @ 1996-09-03  0:00 UTC (permalink / raw)



In article <JSA.96Sep1205656@alexandria>, Jon S Anthony <jsa@alexandria> wrote:
>Hmmm, actually there is another point poking through here: What I had
>in mind was an aggregate where all the fields are specified (as non
>copies) - not the sort of case where you use an _object_ of the type
>for the aggregate.  Actually, I didn't even know you could do this -
>thought that was a simple qualified expression (then again, I guess
>that's what an aggregate is...).

A qualified expression can contain any sort of expression inside the
parens, not just an aggregate.  The syntax special-cases aggregates,
just so you can leave out one pair of parens -- you can write T'(a,b,c)
instead of T'((a,b,c)).  And an initialized allocator contains a
qualified expression.

>Fine.  If that is the reasoning that went into it.  My claim is that
>in the user model it does not have to be a copy.

I suspect you're right -- you *could* define a language feature that
made initialization work the way you want.

>> 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.
>
>Yes, I've done this one too - it is _very_ useful, but not in those
>cases where the discriminants are to be hidden.

I don't understand what you mean, here.  Ada 95 added the
"unknown discrims" feature so you can hide discrims.  E.g.:

    package P is
        type T(<>) is ...
    private
        type T(Length, Width: Integer) is ...
    end P;

>Yup, that is precisely the idea that I had in mind by the notion that
>you would not have to define an initialized allocator as a copying
>operation.  You have nailed down what I really had in mind.  The
>reason allocators _seem_ special here, is that there is no object in
>the _user model_ that is being assigned!
>
>X : T := expression; -- Clearly an assignment IN THE USER MODEL to a T object
>
>X : T_Ref := new T'(...); -- NOT an assignment to a T object
>                          -- IN THE USER MODEL.  In the user model
>                          -- a T_Ref object is being assigned!  Sure,
>                          -- in the nefarious innards of the language
>                          -- model this too has an assignment to a T
>                          -- object - as currently defined.

Well, hmph.  If the user has that model, then the user's model is wrong.
The two cases of initialization are entirely analogous.  In the second
case, the heap object is being explicitly initialized.  Look at the
rules in the RM for the two cases -- you will see a lot of parallels,
and that's intentional.

So, I would claim that if the feature you are looking for (a way to
initialize limited objects with compile-time checking for missing
components) existed, then it should exist for initializing stack objects
*and* heap objects.

>> whereas Ada always uses (essentially) type-equivalence-by-name.  Access
>> parameters are helpful, but that only works for parameters.

>Not when you are using access to class wide types.  That is more or
>less the whole point of such things.  One named type representing whole
>sets of possible structures.  Criminey, that's the whole point!

I'm not sure what that "not" refers to, or the "such things".  You *can*
have an access parameter whose designated type is class-wide.  I do it
all the time, precisely because it doesn't require a bogus
type_conversion.  Unfortunately, you can't do that for other things,
like record components and stand-alone variables.  E.g.:

    type T1 is ...
    type T1_Ptr is access all T1'Class;
    
    type T2 is new T1 with ...
    type T2_Ptr is access all T2'Class;
    
    X: T1_Ptr;
    Y: T2_Ptr;

    X := T1_Ptr(Y); -- Grr.

I find the above type_conversion to be annoying rubbish, because it
can't possibly fail, and it doesn't do anything, and it doesn't tell the
reader of the code anything interesting.  It's nice that I can pass Y to
a parameter of type "access T1'Class", but it's annoying that the same
thing doesn't work for things that aren't parameters.  That was *my*
point.  Did I misunderstand *your* point?

Perhaps we should have defined access-to-tagged to allow implicit
conversions up the hierarchy.  It's a bit tricky to get the overload
resolution rules right, so they don't cause Beaujolais effects, but I
think it's possible.

(By the way, we should not have defined the "access all" feature.  We
should have just made all access types work that way.  There's really no
*important* reason for the language to have both "access Foo" and
"access all Foo".  This design mistake was largely my fault -- during
the language design, I argued strongly for the "all" feature.  I've
since changed my mind, since I end up almost always using "all" anyway.)

- Bob




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-09-02  0:00   ` Jon S Anthony
@ 1996-09-04  0:00     ` Joel VanLaven
  1996-09-05  0:00       ` Robert A Duff
  1996-09-06  0:00     ` Jon S Anthony
  1 sibling, 1 reply; 13+ messages in thread
From: Joel VanLaven @ 1996-09-04  0:00 UTC (permalink / raw)



Jon S Anthony (jsa@alexandria) wrote:
: > > >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.
: > 
: > No, I really think what I was after is the above bit about limited
: > public and non limited private views of tagged types.  To me, not
: > allowing an aggregate is obvious: it is an assignment to the object
: > (not to its separate fields!) and thus illegal for limited types.

: Well, here I'm just in the weeds, having become side tracked by the
: public/private limited/non-limited tagged type issue.  This really has
: nothing to do with what I had in mind, which is really captured by the
: notion of "in place" creation.

  As I did not know much about limited types, and this seemed so interesting
and potentially important to me as a new Ada95 programmer, I read up and
looked around at this.  Here is an interesting take on limited types from
the Annotated Ada95 Reference Manual <7.5:1a> 

"The concept of the value of a limited type is difficult to define, since 
the abstract value of a limited type often extends beyond its physical
representation.  In some sense, values of a limited type cannot be divorced
from their object. Th value is the object."

  This leads me to think that disallowing any sort of "total" initialization
makes sense to preserve the powerful abstraction involved.  However, this is
not what you want.  So, I bring your attention to the concept of a record.
The obvious concept of a record is a way of grouping types into a more
complicated type.  If this were the entire extent of a record we would be
fine.  The problem is that records are given special meaning and usage for
tagged types, interfering with the natural nice things that can be done with
them like aggregate assignment/initialization, etc.  So, consider that the
record is almost undoubtedly in no way actually taking up extra space in the
running program, just as the "extraneous type conversion" isn't really there
(just at compile time, as a sort of compiler directive), and we come to my
solution, albeit possibly a "hack" :).

  In order to extend T to C, define a new record type oh say c_rec like
type c_rec is record
  a:t1;
  b:t2;
...
end reocrd;

type c is new t with record
  rec:c_rec;
end record;

  This allows you to use the nice aggregate assignment features of Ada 
without being stuck on the idea of tagged types as records, using:
obj_ref.rec:=c_rec'(a1,b1,...);

  Using this method as well as the access type conversion you mentioned
earlieri, possibly isolated into a self-defined "in place" creation
subprogram  ought to work fairly well.  The extra record type ought not
add run-time costs, just like the type conversion.  It might not give you
be the most natural way to do what you want, but then again limited types
are severely restricted for good if obscure reasons.  Perhaps you'd rather
use controlled types...?

  If this is a stupid idea or I missed the point, as is quite possible,
don't worry, my ego doesn't hang on this at all :) BTW I really enjoy your
posts, and it is good to here from people doing user-level commercial
applications in my favorite language, keep it up!

-- While the opinions in this message do not represent the opinions of my
-- employers, the technical accuracy or lack there of does represent the
-- quality of my higher education.
--
-- Joel VanLaven
-- 
-- Joel VanLaven




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-08-31  0:00 ` Robert A Duff
  1996-09-02  0:00   ` Jon S Anthony
  1996-09-02  0:00   ` Jon S Anthony
@ 1996-09-04  0:00   ` Jon S Anthony
  1996-09-05  0:00     ` Robert A Duff
  1996-09-05  0:00   ` Jon S Anthony
  3 siblings, 1 reply; 13+ messages in thread
From: Jon S Anthony @ 1996-09-04  0:00 UTC (permalink / raw)



In article <Dx5xHt.423@world.std.com> bobduff@world.std.com (Robert A Duff) writes:

> In article <JSA.96Sep1205656@alexandria>, Jon S Anthony <jsa@alexandria> wrote:
> >Hmmm, actually there is another point poking through here: What I had
> >in mind was an aggregate where all the fields are specified (as non
> >copies) - not the sort of case where you use an _object_ of the type
> >for the aggregate.  Actually, I didn't even know you could do this -
> >thought that was a simple qualified expression (then again, I guess
> >that's what an aggregate is...).
> 
> A qualified expression can contain any sort of expression inside the
> parens, not just an aggregate.  The syntax special-cases aggregates,
> just so you can leave out one pair of parens -- you can write T'(a,b,c)
> instead of T'((a,b,c)).  And an initialized allocator contains a
> qualified expression.

Yes, went back and checked this out too.  Certainly seems reasonable.


> >Fine.  If that is the reasoning that went into it.  My claim is that
> >in the user model it does not have to be a copy.
> 
> I suspect you're right -- you *could* define a language feature that
> made initialization work the way you want.

Yes, quite.


> >> 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.
> >
> >Yes, I've done this one too - it is _very_ useful, but not in those
> >cases where the discriminants are to be hidden.
> 
> I don't understand what you mean, here.  Ada 95 added the
> "unknown discrims" feature so you can hide discrims.  E.g.:

I mean just that.  I am using limited private types with unknown
discriminants so that a client must call the constructor to create any
instances (also => no stack allocations).  I also want to allow some
updates (via interface accessors) to some of the state of such
instances, so using discriminants as the implementation of the state
won't work (can't change them).  Yes, there are ways around this,
but the tradeoffs just aren't in its favor in this particular case.

Hmmm, I think I see where my use of "discriminants are to be hidden"
was a confusing phrase.  All I meant by this one was that in the past
when I've used the "all fields are discriminants" implementation, all
the fields were public and the type was limited.  Then you do just as
you suggest: initialize via a discriminant constraint.


> >Yup, that is precisely the idea that I had in mind by the notion that
> >you would not have to define an initialized allocator as a copying
> >operation.  You have nailed down what I really had in mind.  The
> >reason allocators _seem_ special here, is that there is no object in
> >the _user model_ that is being assigned!
> >
> >X : T := expression; -- Clearly an assignment IN THE USER MODEL to a T object
> >
> >X : T_Ref := new T'(...); -- NOT an assignment to a T object
> >                          -- IN THE USER MODEL.  In the user model
> >                          -- a T_Ref object is being assigned!  Sure,
> >                          -- in the nefarious innards of the language
> >                          -- model this too has an assignment to a T
> >                          -- object - as currently defined.
> 
> Well, hmph.  If the user has that model, then the user's model is wrong.

Shrug.  Well that was easy to say.  Why (no fair saying : "because that
is what the RM says")?


> The two cases of initialization are entirely analogous.  In the second
> case, the heap object is being explicitly initialized.  Look at the
> rules in the RM for the two cases -- you will see a lot of parallels,
> and that's intentional.

Sure, that is indeed how the RM talks about these cases.  Doesn't make
it "right".  The second case is simply one where the idea of the heap
object being first created, then the expression being converted to
type T and then the heap object being assigned the resulting value is
an internal language design issue.  Joe Programmer didn't ask for
those semantics.  It is not even clear that they are all that good a
semantics for this case.  In fact, it is not even clear that thinking
of this as an _initialization_ is even the best way of thinking of it.
They were deemed good and proper by the designer - presumably for
perceived "consistency" or "regularity" reasons - or something.

J.Progammer:

"Hey, I'm creating an object with those values - I'm not creating an
object first and then _initializing_ it after the fact with those
values."  This isn't peculiar at all - it is very similar to what
happens with a discriminant constraint.


> So, I would claim that if the feature you are looking for (a way to
> initialize limited objects with compile-time checking for missing
> components) existed, then it should exist for initializing stack objects
> *and* heap objects.

If you are going to approach it from the "initialize" perspective, you
are quite right.


> >> whereas Ada always uses (essentially) type-equivalence-by-name.  Access
> >> parameters are helpful, but that only works for parameters.
> 
> >Not when you are using access to class wide types.  That is more or
> >less the whole point of such things.  One named type representing whole
> >sets of possible structures.  Criminey, that's the whole point!
> 
> I'm not sure what that "not" refers to, or the "such things".  You *can*

Yes, this is my goof on not supplying your correct context.  Parsimony
can sometimes lead one into the weeds!  Let's see here, I think I have
the original....

> >> 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.

So, the "not" refers to the fact that with access to class wide types
the "structure equivalent" semantics _are_ what you get.  _One_ named
type being allowed to refer to whole sets of possible structures.  But
there are these cases where it doesn't work - because of interaction
with other "features".


> have an access parameter whose designated type is class-wide.  I do it
> all the time, precisely because it doesn't require a bogus

Right.  So do I.  In fact that is sort of how this entire thread got
started: I had such a class wide access type, but could not use it
because of the "initialization" semantics for allocators (which choked
on my limited type)!


>     X := T1_Ptr(Y); -- Grr.
> 
> I find the above type_conversion to be annoying rubbish, because it
> can't possibly fail, and it doesn't do anything, and it doesn't tell the
> reader of the code anything interesting.  It's nice that I can pass Y to

That's very similar to what I hit in the case starting this thread.
All I wanted to do was create a list of "class-wide pointers" (forgive
the somewhat sloppy language) which happened to be pointing to objects
of one of the descendent types of the original type used in definition
of the class wide access type.  These objects are created as they are
added to the list.  Why should I have to use a more specific access
type in this scenario?  This is not only superfluous (the wider type
can't fail), annoying, and confusing to subsequent readers, it is also
error prone.


> a parameter of type "access T1'Class", but it's annoying that the same
> thing doesn't work for things that aren't parameters.  That was *my*
> point.  Did I misunderstand *your* point?

I think we just talked past one another (each missing the other's
point) - such is news...


> Perhaps we should have defined access-to-tagged to allow implicit
> conversions up the hierarchy.  It's a bit tricky to get the overload
> resolution rules right, so they don't cause Beaujolais effects, but I
> think it's possible.

That would have been nice for the user - but as you say, tricky to get
right.


> (By the way, we should not have defined the "access all" feature.  We
> should have just made all access types work that way.  There's really no
> *important* reason for the language to have both "access Foo" and
> "access all Foo".  This design mistake was largely my fault -- during
> the language design, I argued strongly for the "all" feature.  I've
> since changed my mind, since I end up almost always using "all" anyway.)

Yes, that was a goof.  But an understandable one and with good
reasons.  This is the sort of thing that is hard to get right without
actual field use in real applications.  I suppose you could've lucked
out if you'd have turned it around.  Having had the "all" semantics be
the default and then required some indication for the case where
specialized pools were going to be used.  That way, the (supposed)
special indicator wouldn't have become what has turned out to be by
far the common one.

/Jon
-- 
Jon Anthony
Organon Motives, Inc.
1 Williston Road, Suite 4
Belmont, MA 02178

617.484.3383
jsa@organon.com





^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-09-04  0:00   ` Jon S Anthony
@ 1996-09-05  0:00     ` Robert A Duff
  0 siblings, 0 replies; 13+ messages in thread
From: Robert A Duff @ 1996-09-05  0:00 UTC (permalink / raw)



In article <JSA.96Sep4163853@alexandria>, Jon S Anthony <jsa@alexandria> wrote:
>> The two cases of initialization are entirely analogous.  In the second
>> case, the heap object is being explicitly initialized.  Look at the
>> rules in the RM for the two cases -- you will see a lot of parallels,
>> and that's intentional.
>
>Sure, that is indeed how the RM talks about these cases.  Doesn't make
>it "right".

True, it doesn't make it right, but I think it *is* right, nonetheless.
Your complaint was, you can't initialize a limited heap variable in a
way that prevents you from forgetting some components.  Initializing
with an aggregate gives that nice feature, but it doesn't work for
limited types.  A valid complaint, perhaps, but it's equally valid for
stack objects.

>...  The second case is simply one where the idea of the heap
>object being first created, then the expression being converted to
>type T and then the heap object being assigned the resulting value is
>an internal language design issue.

Actually, the expression is evaluated first, since it's discriminants or
bounds might determine what to create.  Then the object is created.

>...  Joe Programmer didn't ask for
>those semantics.  It is not even clear that they are all that good a
>semantics for this case.  In fact, it is not even clear that thinking
>of this as an _initialization_ is even the best way of thinking of it.
>They were deemed good and proper by the designer - presumably for
>perceived "consistency" or "regularity" reasons - or something.
>
>J.Progammer:
>
>"Hey, I'm creating an object with those values - I'm not creating an
>object first and then _initializing_ it after the fact with those
>values."  This isn't peculiar at all - it is very similar to what
>happens with a discriminant constraint.

Fine.  All I was saying is that the same arguments apply equally to both
"new T'(...)" and "X: T := ...;".

>So, the "not" refers to the fact that with access to class wide types
>the "structure equivalent" semantics _are_ what you get.  _One_ named
>type being allowed to refer to whole sets of possible structures.

Not quite.  For named access-to-class-wide types, you get named
equivalence.  For anonymous access-to-class-wide types, you get
structural equivalence.  And the latter is only allowed in certain cases
(parameters and discriminants).

>I think we just talked past one another (each missing the other's
>point) - such is news...

;-)

>> Perhaps we should have defined access-to-tagged to allow implicit
>> conversions up the hierarchy.  It's a bit tricky to get the overload
>> resolution rules right, so they don't cause Beaujolais effects, but I
>> think it's possible.
>
>That would have been nice for the user - but as you say, tricky to get
>right.

Ah, well.

>> (By the way, we should not have defined the "access all" feature.  We
>> should have just made all access types work that way.  There's really no
>> *important* reason for the language to have both "access Foo" and
>> "access all Foo".  This design mistake was largely my fault -- during
>> the language design, I argued strongly for the "all" feature.  I've
>> since changed my mind, since I end up almost always using "all" anyway.)
>
>Yes, that was a goof.  But an understandable one and with good
>reasons.  This is the sort of thing that is hard to get right without
>actual field use in real applications.  I suppose you could've lucked
>out if you'd have turned it around.  Having had the "all" semantics be
>the default and then required some indication for the case where
>specialized pools were going to be used.  That way, the (supposed)
>special indicator wouldn't have become what has turned out to be by
>far the common one.

True, but the non-all syntax matches what Ada 83 does, so it was natural
to leave that alone, and add on the "all" syntax meaning "you can do
conversions when you couldn't in Ada 83".  Anyway, typing "all" all the
time is a very minor annoyance -- what annoys me more is have two
features in the language, where one would suffice.

- Bob




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-09-04  0:00     ` Joel VanLaven
@ 1996-09-05  0:00       ` Robert A Duff
  0 siblings, 0 replies; 13+ messages in thread
From: Robert A Duff @ 1996-09-05  0:00 UTC (permalink / raw)



In article <1996Sep4.183415.17277@ocsystems.com>,
Joel VanLaven <jvl@ocsystems.com> wrote:
>type c is new t with record
>  rec:c_rec;
>end record;
>
>  This allows you to use the nice aggregate assignment features of Ada 
>without being stuck on the idea of tagged types as records, using:
>obj_ref.rec:=c_rec'(a1,b1,...);

This suggestion makes a lot of sense to me.  T and C might be limited,
but C_Rec might be non-limited, thus allowing aggregates.

Ada's aggregates have this nice feature of preventing you from
forgetting some componenents.  (Especially when you have existing
aggregates in your code, and you *add* a component to the type.)  But
with private extensions of private extensions of ... you don't even know
what your parent's components are.  This suggestion allows you to get
the nice feature of aggregates for the one little extension part you
know about, which seems nice.

- Bob




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-08-31  0:00 ` Robert A Duff
                     ` (2 preceding siblings ...)
  1996-09-04  0:00   ` Jon S Anthony
@ 1996-09-05  0:00   ` Jon S Anthony
  1996-09-05  0:00     ` Robert A Duff
  3 siblings, 1 reply; 13+ messages in thread
From: Jon S Anthony @ 1996-09-05  0:00 UTC (permalink / raw)



In article <1996Sep4.183415.17277@ocsystems.com> jvl@ocsystems.com (Joel VanLaven) writes:

> Jon S Anthony (jsa@alexandria) wrote:
> 
> : Well, here I'm just in the weeds, having become side tracked by the
> : public/private limited/non-limited tagged type issue.  This really has
> : nothing to do with what I had in mind, which is really captured by the
> : notion of "in place" creation.
> 
>   As I did not know much about limited types, and this seemed so interesting
> and potentially important to me as a new Ada95 programmer, I read up and
> looked around at this.  Here is an interesting take on limited types from
> the Annotated Ada95 Reference Manual <7.5:1a> 
> 
> "The concept of the value of a limited type is difficult to define, since 
> the abstract value of a limited type often extends beyond its physical
> representation.  In some sense, values of a limited type cannot be divorced
> from their object. Th value is the object."

Actually, this supports my notion that the idea of "initialization"
after creation of the limited object (in an allocator in particular)
is not the best way of thinking of it.  The "value is the object" bit
hits this pretty well.  In fact, that is pretty much _exactly_ the
point.  So, since the design team thought the same here, the whole
thing becomes rather mysterious as to why things turned out as they
did.


>   This leads me to think that disallowing any sort of "total"
> initialization makes sense to preserve the powerful abstraction
> involved.

I don't understand what you mean here.  The fact is, you can mung a
limited thing to your heart's content (field by field), you just can't
assign to such an object (and that is indeed a _very_ good thing).
Make it private and no _client_ can mung it either (they can't see the
implementation).


> fine.  The problem is that records are given special meaning and usage for
> tagged types, interfering with the natural nice things that can be done with
> them like aggregate assignment/initialization, etc.

???, you can do this sort of stuff just fine with tagged (record) types.
What do you mean by "interfering"???

    package P is
        type X is tagged record
            i,j,k : integer;
        end record;
        ...
    end P;

    with P;
    procedure My_Proc is
        Obj : P.X := (1,2,3); -- Happy as a clam
        ...
    end My_Proc;


>   In order to extend T to C, define a new record type oh say c_rec like
> type c_rec is record
>   a:t1;
>   b:t2;
> ...
> end reocrd;
> 
> type c is new t with record
>   rec:c_rec;
> end record;
> 
>   This allows you to use the nice aggregate assignment features of Ada 
> without being stuck on the idea of tagged types as records, using:
> obj_ref.rec:=c_rec'(a1,b1,...);

The problem (well, the one at the center of this thread anyway) has
nothing at all to do with tagged types.  It concerns limited types and
"initialized" allocators.  So, presumably T is the _limited_ type that
I originally mentioned (and thus C is limited too).

This hack you give doesn't really work for this problem because at the
end of the day, C still has an implementation which cannot have values
during an allocation:

    cptr := new c'(...); -- still illegal

Now, you can say that this _reduces_ the potential missing field
errors when giving values field by field for multiple new fields
(since you only have "one" new field), but it also requires another
record type whenever you extend and is rather unnatural.

I actually considered this hack, but rejected it because it had all
the original bad aspects plus requiring new types for every extension.
To me, in the particular case in question, the tradeoffs went against
it.  But it is certainly a sensible idea.


>   Using this method as well as the access type conversion you mentioned
> earlieri, possibly isolated into a self-defined "in place" creation
> subprogram  ought to work fairly well.

What do you mean by "self-defined in place creation" subprogram?  The
problem is, the ARM just doesn't define such "in place creation".
But, as I have argued (and as the above AARM quote seems to support)
this was a mistake (at least for limited types).


> The extra record type ought not
> add run-time costs, just like the type conversion.

Ah, so that's what you meant by "extra".  You are correct - no extra
space will be allocated.


> It might not give you be the most natural way to do what you want,
> but then again limited types are severely restricted for good if
> obscure reasons.  Perhaps you'd rather use controlled types...?

For this case, controlled types aren't relevant and if they were, I'd
be using limited_controlled types and be right back in the same boat.
Also, note that limited types can be munged all over as long as you
have access to the full type definition (so that you can see the
fields).  In the case in question this is definitely true (since it is
located in the _implementation_ of the interface!)  So, in this
context, limited only prevents certain odd-ball errors (such as the
violation of limited fields in extensions).


>   If this is a stupid idea or I missed the point, as is quite possible,

Not at all.  In general you seem to have the point.  And your hack was
indeed a hack that I did consider - thanks for the effort!


> don't worry, my ego doesn't hang on this at all :) BTW I really
> enjoy your posts, and it is good to here from people doing
> user-level commercial applications in my favorite language, keep it
> up!

Thanks - I try.  But often fail :-(.  Are you doing commercial stuff?
If so, excellent!

/Jon
-- 
Jon Anthony
Organon Motives, Inc.
1 Williston Road, Suite 4
Belmont, MA 02178

617.484.3383
jsa@organon.com





^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-09-05  0:00   ` Jon S Anthony
@ 1996-09-05  0:00     ` Robert A Duff
  0 siblings, 0 replies; 13+ messages in thread
From: Robert A Duff @ 1996-09-05  0:00 UTC (permalink / raw)



In article <JSA.96Sep5151217@alexandria>, Jon S Anthony <jsa@alexandria> wrote:
>Actually, this supports my notion that the idea of "initialization"
>after creation of the limited object (in an allocator in particular)
>is not the best way of thinking of it.  The "value is the object" bit
>hits this pretty well.  In fact, that is pretty much _exactly_ the
>point.  So, since the design team thought the same here, the whole
>thing becomes rather mysterious as to why things turned out as they
>did.

Well, the Ada 9X design team thought this.  And I remember writing this
particular paragraph after much discussion with Tucker, and rather late
in the Ada 9X project.

But Ada 95 inherited the initialization mechanisms from Ada 83, and
there was no pressure to change them (no "Revision Requests" along those
lines, as far as I remember).  Frankly, it never occurred to me to
change the initialization stuff.  (Although it apparently did occur to
Henry Baker, before Ada 9X.)  Nothing is really broken -- there's just a
nice piece-to-have feature that's not there for limited types.  (Most
languages don't have that feature for *any* types, and don't have
limited types at all!  Think about an aggregate (or whatever it's
called) in C, where any missing fields are conveniently filled with
zeros.

>The problem (well, the one at the center of this thread anyway) has
>nothing at all to do with tagged types.  It concerns limited types and
>"initialized" allocators.  So, presumably T is the _limited_ type that
>I originally mentioned (and thus C is limited too).

You misunderstand the suggestion.  Make T non-limited, but C (containing
a T) limited.  It works for tagged and untagged.

- Bob




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-09-02  0:00   ` Jon S Anthony
  1996-09-04  0:00     ` Joel VanLaven
@ 1996-09-06  0:00     ` Jon S Anthony
  1 sibling, 0 replies; 13+ messages in thread
From: Jon S Anthony @ 1996-09-06  0:00 UTC (permalink / raw)



In article <DxA7AB.CLB@world.std.com> bobduff@world.std.com (Robert A Duff) writes:

> 
> In article <JSA.96Sep5151217@alexandria>, Jon S Anthony <jsa@alexandria> wrote:
> >Actually, this supports my notion that the idea of "initialization"
> >after creation of the limited object (in an allocator in particular)
> >is not the best way of thinking of it.  The "value is the object" bit
> >hits this pretty well.  In fact, that is pretty much _exactly_ the
> >point.  So, since the design team thought the same here, the whole
> >thing becomes rather mysterious as to why things turned out as they
> >did.
> 
> Well, the Ada 9X design team thought this.  And I remember writing this
> particular paragraph after much discussion with Tucker, and rather late
> in the Ada 9X project.
> 
> But Ada 95 inherited the initialization mechanisms from Ada 83, and
> there was no pressure to change them (no "Revision Requests" along those
> lines, as far as I remember).  Frankly, it never occurred to me to
> change the initialization stuff.  (Although it apparently did occur to
> Henry Baker, before Ada 9X.)

Ah.  You know, I am really beginning to see why Henry Baker is _so_
frustrated by this area of Ada95.  The only reason why this is an
issue for me at all is because of memory allocation/GC issues.  So
close, yet so far... ;-)


> Nothing is really broken -- there's just a nice piece-to-have
> feature that's not there for limited types.  (Most languages don't
> have that feature for *any* types, and don't have limited types at
> all!  Think about an aggregate (or whatever it's called) in C, where
> any missing fields are conveniently filled with zeros.

Oh, no argument there.  Rest assured that I know which end my bread's
buttered on in this regard.


> >The problem (well, the one at the center of this thread anyway) has
> >nothing at all to do with tagged types.  It concerns limited types and
> >"initialized" allocators.  So, presumably T is the _limited_ type that
> >I originally mentioned (and thus C is limited too).
> 
> You misunderstand the suggestion.  Make T non-limited, but C (containing
> a T) limited.  It works for tagged and untagged.

Huh?  You've lost me.  The whole point is that T must be limited.  It's
the parent that client's know about.  C is a _descendent_ of T and again
knowable to clients.  The issue involves the _implementation_ of T (and
thus C).  My understanding was that the _implementation_ of these should
proceed by having another (hidden) record type which would then constitute
the single field of T (or C or ...):

    type T is tagged limited private;
    type T_Ref is access all T'Class;
...
private
    type T_Impl is record
        f1:...
        f2:...
        ...
    end record;

    type T is tagged limited record
        Impl: T_Impl;
    end record;
...

    type C is new T with private;
    type C_Ref is access C;
...
private
    type C_Impl is record
        f1:...
        f2:...
        ...
    end record;

    type C is new T with record
        Impl: C_Impl;
    end record;
...
And so on.  Then in the bodies of operations you can do this:

    Result_List : ... the CarCdr with Car access all T'Class thing
    X : C_Ref;

    X := new C; -- Still the same old problem
    X.Impl := (f1 => ..., f2 => ..., ...); -- helps with multi field rubbish
    Result_List := T_Ref(X) + Result_List; -- Same rubbish here too.

Isn't this the idea????  This is the hack I meant when I said that it
was one that I considered but rejected and I thought it was the same as
the suggested one.  Not true?  If not, I guess I'm still not clear on
what the suggestion is.

/Jon
-- 
Jon Anthony
Organon Motives, Inc.
1 Williston Road, Suite 4
Belmont, MA 02178

617.484.3383
jsa@organon.com





^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Allocating "initialized" limited types...
  1996-09-02  0:00   ` Jon S Anthony
  1996-09-03  0:00     ` Robert A Duff
@ 1996-09-06  0:00     ` Jon S Anthony
  1 sibling, 0 replies; 13+ messages in thread
From: Jon S Anthony @ 1996-09-06  0:00 UTC (permalink / raw)



In article <Dx8Js2.5pq@world.std.com> bobduff@world.std.com (Robert A Duff) writes:

> In article <JSA.96Sep4163853@alexandria>, Jon S Anthony <jsa@alexandria> wrote:
> >> The two cases of initialization are entirely analogous.  In the second
> >> case, the heap object is being explicitly initialized.  Look at the
> >> rules in the RM for the two cases -- you will see a lot of parallels,
> >> and that's intentional.
> >
> >Sure, that is indeed how the RM talks about these cases.  Doesn't make
> >it "right".
> 
> True, it doesn't make it right, but I think it *is* right, nonetheless.
> Your complaint was, you can't initialize a limited heap variable in a
> way that prevents you from forgetting some components.  Initializing
> with an aggregate gives that nice feature, but it doesn't work for
> limited types.  A valid complaint, perhaps, but it's equally valid for
> stack objects.

Actually, my "complaint" was why are allocator semantics with
qualified expressions not simply "creation in place" - forget after
the fact "initialization".  Now, this stemmed mostly from the context
of limited types and I would think it just fine if they alone had
these special semantics (as they are treated specially in many
places).  And it certainly appears to make sense to generalize this to
include stack allocations.


> Actually, the expression is evaluated first, since it's discriminants or
> bounds might determine what to create.  Then the object is created.

picky! picky! :-)


> Fine.  All I was saying is that the same arguments apply equally to both
> "new T'(...)" and "X: T := ...;".

I don't think I disagreed with this.  Only tried to point out why the
allocator case _seems_ different.


> >So, the "not" refers to the fact that with access to class wide types
> >the "structure equivalent" semantics _are_ what you get.  _One_ named
> >type being allowed to refer to whole sets of possible structures.
>
> Not quite.  For named access-to-class-wide types, you get named
> equivalence.  For anonymous access-to-class-wide types, you get
> structural equivalence.  And the latter is only allowed in certain
> cases (parameters and discriminants).

Well, you get named equivalence for the access type.  But you do get a
"structural equivalence" (modulo the parent) for the designated types.
And you get "operational equivalence" with no hitch.  You know all this
but it is all I meant:


type T is tagged ...
type T_Ref is access all T'Class;
...
    procedure Op ( X : access T ); -- or just T
...
type C1 is new T...
type C2 is new C1 ...
type C3 is new T ...
    procedure Fop ( X : access C3 ); -- or just C3
...

    procedure My_Op ( X : T_Ref ) is
       Ref : T_Ref := new C3;
       --
       -- In here any operation on any descendent of T can be invoked
       -- on X or Ref, modulo runtime constraints for the current
       -- specific type of the designated object.  And any field of T
       -- is accessable irrespective of the specific type of the 
       -- designated object.
...
       Fop(Ref);
       Op(X);
       Op(Ref);
...
       Ref := 
...
etc.


Re: [To _all_ or not to _all_...]
> True, but the non-all syntax matches what Ada 83 does, so it was natural
> to leave that alone, and add on the "all" syntax meaning "you can do
> conversions when you couldn't in Ada 83".  Anyway, typing "all" all the
> time is a very minor annoyance -- what annoys me more is have two
> features in the language, where one would suffice.

Ah - the joys of backward compatibility.  Not to worry - just imagine
how Bjarne must feel! :-)

/Jon
-- 
Jon Anthony
Organon Motives, Inc.
1 Williston Road, Suite 4
Belmont, MA 02178

617.484.3383
jsa@organon.com





^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~1996-09-06  0:00 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1996-08-30  0:00 Allocating "initialized" limited types Jon S Anthony
1996-08-31  0:00 ` Robert A Duff
1996-09-02  0:00   ` Jon S Anthony
1996-09-04  0:00     ` Joel VanLaven
1996-09-05  0:00       ` Robert A Duff
1996-09-06  0:00     ` Jon S Anthony
1996-09-02  0:00   ` Jon S Anthony
1996-09-03  0:00     ` Robert A Duff
1996-09-06  0:00     ` Jon S Anthony
1996-09-04  0:00   ` Jon S Anthony
1996-09-05  0:00     ` Robert A Duff
1996-09-05  0:00   ` Jon S Anthony
1996-09-05  0:00     ` Robert A Duff

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox