comp.lang.ada
 help / color / mirror / Atom feed
From: jsa@alexandria (Jon S Anthony)
Subject: Re: Allocating "initialized" limited types...
Date: 1996/09/04
Date: 1996-09-04T00:00:00+00:00	[thread overview]
Message-ID: <JSA.96Sep4163853@alexandria> (raw)
In-Reply-To: Dx0q2E.2Bw@world.std.com


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





  parent reply	other threads:[~1996-09-04  0:00 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
1996-09-05  0:00     ` Robert A Duff
1996-09-05  0:00   ` Jon S Anthony
1996-09-05  0:00     ` Robert A Duff
replies disabled

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