Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Indefinite Containers of Indefinite Private Types

131 views
Skip to first unread message

Jeffrey R. Carter

unread,
Aug 3, 2015, 10:23:26 PM8/3/15
to
This is legal:

package Indefinite1 is
type T (<>) is private;
private -- Indefinite1
type T is new String;
end Indefinite1;

with Indefinite1;
with Ada.Containers.Indefinite_Vectors;

package Indefinite2 is
use type Indefinite1.T;

package Lists is new Ada.Containers.Indefinite_Vectors
(Index_Type => Positive, Element_Type => Indefinite1.T);
end Indefinite2;

But this isn't:

with Ada.Containers.Indefinite_Vectors;

package Indefinite1 is
type T (<>) is private;
private -- Indefinite1
package Lists is new Ada.Containers.Indefinite_Vectors
(Index_Type => Positive, Element_Type => T);

type T is new String;
end Indefinite1;

It seems to me that both instantiations have all the information they need.
Probably I'm missing something, but why is the latter illegal?

--
Jeff Carter
"English bed-wetting types."
Monty Python & the Holy Grail
15

Niklas Holsti

unread,
Aug 4, 2015, 1:40:38 AM8/4/15
to
I'm not sure that I have understood your question correctly -- are you
asking for the RM rule that makes this illegal, or for the reason behind
that rule?

At the point of instantiation in the second case, "T" is a partial view
of the type. RM 7.3(5) says "... Similarly, before the full declaration,
the name of the partial view cannot be used in a generic_instantiation
or in a representation item."

As to why this rule exists, I suspect it has to do with the "rechecks"
discussed in the annotated RM 12.3(11) where the legality of an
instantiation is checked by comparing the actual types with the _full_
declaration of the generic (not only with the declarations of the
generic formals). It might be difficult to apply these rechecks if the
actual type is only a partial view.

The second case becomes legal if the full declaration of type T is moved
to occur before the instantiation -- as happens in the first case -- but
you probably knew that.

--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .

Jeffrey R. Carter

unread,
Aug 4, 2015, 2:56:28 PM8/4/15
to
On 08/03/2015 10:40 PM, Niklas Holsti wrote:
>
> I'm not sure that I have understood your question correctly -- are you asking
> for the RM rule that makes this illegal, or for the reason behind that rule?

Sorry if I was unclear. I know the ARM prohibits using an uncompleted private
type as the actual for a generic formal. I'm wondering why this applies to the
case of a generic formal indefinite private type.

Reading that leads me to think that I should have used a subject referring to
generic formal indefinite private types rather than indefinite containers.

> At the point of instantiation in the second case, "T" is a partial view of the
> type. RM 7.3(5) says "... Similarly, before the full declaration, the name of
> the partial view cannot be used in a generic_instantiation or in a
> representation item."

Right. This rule has the advantage of being simple. It seems to me it may have
the disadvantage of disallowing feasible instantiations.

> As to why this rule exists, I suspect it has to do with the "rechecks" discussed
> in the annotated RM 12.3(11) where the legality of an instantiation is checked
> by comparing the actual types with the _full_ declaration of the generic (not
> only with the declarations of the generic formals). It might be difficult to
> apply these rechecks if the actual type is only a partial view.

What a generic can do with a formal indefinite private type is quite limited.
Nothing it can do seems to me to need to know the full type definition. Maybe
I've overlooked something, or maybe there's a good reason why something I don't
think needs the full definition actually does. I'm curious whether such
instantiations could be legal, and what I missed if they can't.

> The second case becomes legal if the full declaration of type T is moved to
> occur before the instantiation -- as happens in the first case -- but you
> probably knew that.

Yes, of course. The examples are simplified from a more complex case where the
container is used in the full type definition. This can be achieved by adding
some additional code that is essentially noise, or by using access types.
Avoiding access types is worth adding noise, but it would be nice if the noise
were unnecessary.

--
Jeff Carter
"Have you gone berserk? Can't you see that that man is a ni?"
Blazing Saddles
38

Randy Brukardt

unread,
Aug 4, 2015, 4:47:25 PM8/4/15
to
"Jeffrey R. Carter" <spam.jrc...@spam.not.acm.org> wrote in message
news:mpr1po$4sn$1...@dont-email.me...
> On 08/03/2015 10:40 PM, Niklas Holsti wrote:
>>
>> I'm not sure that I have understood your question correctly -- are you
>> asking
>> for the RM rule that makes this illegal, or for the reason behind that
>> rule?
>
> Sorry if I was unclear. I know the ARM prohibits using an uncompleted
> private
> type as the actual for a generic formal. I'm wondering why this applies to
> the
> case of a generic formal indefinite private type.

An amazing amount of ARG hair has been pulled over this issue. There are
about 10 AIs on the topic, none of which have gotten particularly close to
being accepted.

The very short answer is that an object can be created of such a type, so it
doesn't help that the type is indefinite (the problems with allowing this
tend to be in freezing and elaboration rules, particularly in not changing
the rules incompatibly).

Specifically:

generic
type T (<>) is private;
function Creator return T;
package G is
Obj : T := Creator; -- Legal.
end G;

Note that such an object would be illegal before the full completion of the
private type. So, if you put that object declaration into the body, you have
a contract model violation. Therein is the problem.

One could imagine having a declaration for the generic (perhaps an aspect?)
that would allow such instantiations (and disallow such objects), but again
there has been little traction for such proposals, all of which are quite
complex to describe and implement.

...
>> At the point of instantiation in the second case, "T" is a partial view
>> of the
>> type. RM 7.3(5) says "... Similarly, before the full declaration, the
>> name of
>> the partial view cannot be used in a generic_instantiation or in a
>> representation item."
>
> Right. This rule has the advantage of being simple. It seems to me it may
> have
> the disadvantage of disallowing feasible instantiations.

Sure, but there can't be any objects in the generic. Even if there isn't a
constructor function, any parameter of type T could have been used in "new".

>> I suppose this to do with the "rechecks" discussed
>> in the annotated RM 12.3(11) where the legality of an instantiation is
>> checked
>> by comparing the actual types with the _full_ declaration of the generic
>> (not
>> only with the declarations of the generic formals). It might be difficult
>> to
>> apply these rechecks if the actual type is only a partial view.
>
> What a generic can do with a formal indefinite private type is quite
> limited.
> Nothing it can do seems to me to need to know the full type definition.
> Maybe
> I've overlooked something, or maybe there's a good reason why something I
> don't
> think needs the full definition actually does. I'm curious whether such
> instantiations could be legal, and what I missed if they can't.

Declaring an object surely needs the full declaration, and I showed above
how to do it. Recall that the elaboration of the body occurs at the point of
the instance (before the full declaration of the private type).

One can make signature packages with formal incomplete types (which can be
instantiated with private types before the completion), but it's hard to
make a useful container that way. (It's not impossible, but you have to use
more access types than I find comfortable.)

>> The second case becomes legal if the full declaration of type T is moved
>> to
>> occur before the instantiation -- as happens in the first case -- but you
>> probably knew that.
>
> Yes, of course. The examples are simplified from a more complex case where
> the
> container is used in the full type definition. This can be achieved by
> adding
> some additional code that is essentially noise, or by using access types.
> Avoiding access types is worth adding noise, but it would be nice if the
> noise
> were unnecessary.

I agree, but the ARG has not been able to find an acceptable solution to
this problem. And we surely have tried:

AI95-00359-01, AI95-00359-02, AI95-00359-03, AI95-00359-04, AI05-0074-1,
AI05-0074-2, AI05-0074-3, AI05-0074-4, AI05-0074-5 (AI05-0011-1 was also
related, but it was a duplicate).

We're pretty much pooped out on this topic. Sometimes there just is no
answer that can get a consensus.

Randy.


Jeffrey R. Carter

unread,
Aug 4, 2015, 4:56:59 PM8/4/15
to
On 08/04/2015 01:47 PM, Randy Brukardt wrote:
>
> An amazing amount of ARG hair has been pulled over this issue. There are
> about 10 AIs on the topic, none of which have gotten particularly close to
> being accepted.
>
> The very short answer is that an object can be created of such a type, so it
> doesn't help that the type is indefinite (the problems with allowing this
> tend to be in freezing and elaboration rules, particularly in not changing
> the rules incompatibly).
>
> Specifically:
>
> generic
> type T (<>) is private;
> function Creator return T;
> package G is
> Obj : T := Creator; -- Legal.
> end G;
>
> Note that such an object would be illegal before the full completion of the
> private type. So, if you put that object declaration into the body, you have
> a contract model violation. Therein is the problem.

Of course. I guess I was thinking too much in terms of what a container does
with the type and not in general.

> One could imagine having a declaration for the generic (perhaps an aspect?)
> that would allow such instantiations (and disallow such objects), but again
> there has been little traction for such proposals, all of which are quite
> complex to describe and implement.

I can guess so. Probably a new generic formal type would be desired. Meanwhile
I'll put up with the noise.

Randy Brukardt

unread,
Aug 6, 2015, 2:49:12 PM8/6/15
to
"Jeffrey R. Carter" <spam.jrc...@spam.not.acm.org> wrote in message
news:mpr8rn$33n$1...@dont-email.me...
> On 08/04/2015 01:47 PM, Randy Brukardt wrote:
...
>> One could imagine having a declaration for the generic (perhaps an
>> aspect?)
>> that would allow such instantiations (and disallow such objects), but
>> again
>> there has been little traction for such proposals, all of which are quite
>> complex to describe and implement.
>
> I can guess so. Probably a new generic formal type would be desired.
> Meanwhile
> I'll put up with the noise.

That's one possibility. We could call it a generic private type. Oops --
that name is taken, and alternative names are annoying. (The idea of course
would be similar to the generic incomplete type; the restrictions on the use
of a private type would be enforced on the uses of the generic formal type.)

We've also looked at declarations (maybe an aspect) for the generic as a
whole, there was a proposal for a "forward" declaration for the generic
(that is, you'd be able to separate the visible part of the generic from the
actual instance, just like in other kinds of packages), and a proposal to
change the freezing to be exactly like a macro (meaning a break in the
contract model, and a horror to implement on top of that). We also found
that there is a workaround of sorts using a child package to hold the
instantiation, which works so long as the private type doesn't use something
from the instantiation (usually a cursor for a container) in its full
declaration. The existence of the workaround lowers the priority of finding
a fix, and given the difficulty of doing so, we pretty much gave up. I'm
sure we'll revisit it someday.

Randy.


Jeffrey R. Carter

unread,
Aug 6, 2015, 4:12:36 PM8/6/15
to
On 08/06/2015 11:49 AM, Randy Brukardt wrote:
>
> That's one possibility. We could call it a generic private type. Oops --
> that name is taken, and alternative names are annoying. (The idea of course
> would be similar to the generic incomplete type; the restrictions on the use
> of a private type would be enforced on the uses of the generic formal type.)
>
> We've also looked at declarations (maybe an aspect) for the generic as a
> whole, there was a proposal for a "forward" declaration for the generic
> (that is, you'd be able to separate the visible part of the generic from the
> actual instance, just like in other kinds of packages), and a proposal to
> change the freezing to be exactly like a macro (meaning a break in the
> contract model, and a horror to implement on top of that). We also found
> that there is a workaround of sorts using a child package to hold the
> instantiation, which works so long as the private type doesn't use something
> from the instantiation (usually a cursor for a container) in its full
> declaration. The existence of the workaround lowers the priority of finding
> a fix, and given the difficulty of doing so, we pretty much gave up. I'm
> sure we'll revisit it someday.

I looked at some of the AIs you mentioned and saw there were a number of ideas.
The child-pkg workaround involves using an access type, so it doesn't seem to
gain anything over using access types directly, and is less attractive than
access-free noise, which seems to me to be another work around not considered in
the discussion I looked at.

The problem seems to be that there is a single instantiation for both the spec
and body, and the body occurs and is elaborated immediately at the point of the
instantiation. Another language might instantiate the spec and body separately,
allowing the body to be instantiated after the full type. There were some
suggestions in the AIs along that line, but couched in terms of delaying
freezing rather than separation of spec and body.

Maybe something like

package P is
type T (<>) is private;
private
package Lists is new Indefinite_Vectors
(Index_Type => Positive, Element_Type => T)
with not body;

type T is record
List : Lists.Vector;
end record;
end P;

package body P is
package body Lists is new Indefinite_Vectors;
...

I guess I'm beating a dead hippopotamus here.

--
Jeff Carter
"Facts do not cease to exist because they are ignored."
Aldous Huxley
134

Randy Brukardt

unread,
Aug 7, 2015, 3:49:07 PM8/7/15
to
"Jeffrey R. Carter" <spam.jrc...@spam.not.acm.org> wrote in message
news:mq0f0g$7im$1...@dont-email.me...
I had suggested something along this line (not exactly this, though), but at
least some people were trying to do this without making any work for the
client. But of course that causes incompatibilties; which led to arguments
about how important the incompatibilities are, and that tends to lead
nowhere.

> I guess I'm beating a dead hippopotamus here.

Yup.

Randy.


Bob Duff

unread,
Aug 7, 2015, 4:13:33 PM8/7/15
to
"Jeffrey R. Carter" <spam.jrc...@spam.not.acm.org> writes:

> Yes, of course. The examples are simplified from a more complex case where the
> container is used in the full type definition. This can be achieved by adding
> some additional code that is essentially noise, or by using access types.
> Avoiding access types is worth adding noise, but it would be nice if the noise
> were unnecessary.

I'm curious what the "noise" looks like in your case.

Last time I ran into this problem I think I ended up using a workaround
that involved access types. I don't remember the details.

- Bob

Jeffrey R. Carter

unread,
Aug 7, 2015, 4:45:27 PM8/7/15
to
It involves using tagged types, type extension, and a container of a class-wide
type:

with Ada.Containers.Indefinite_Vectors;

package P is
type T (<>) is private;
private
type Root is tagged null record;

package Lists is new Ada.Containers.Vectors
(Index_Type => Positive, Element_Type => Root'Class);

type T is new Root with record
List : Lists.Vector;
end T;
end P;

The only reason for the type extension is to get the instantiation that can be
used in the full declaration of T. The only objects that will be stored in a
vector are of type T. In addition to the noise of the Root type and the
extension for T, there are type conversions required that are part of the noise.

--
Jeff Carter
"From this day on, the official language of San Marcos will be Swedish."
Bananas
28
0 new messages