Version 1.2 of ai05s/ai05-0060-1.txt
!standard E.2.2(9/1) 07-08-04 AI05-0060-1/00
!standard E.2.2(9.2/1)
!class binding interpretation 07-08-04
!status work item 07-08-04
!status received 07-06-19
!priority Low
!difficulty Hard
!qualifier Omission
!subject The definition of Remote access types is too limiting
!summary
** TBD **
!question
(1) E.2.2(9-9.2/1) define what a remote access type can designate. This does not include
a class-wide interface. But an interface is very similar to an abstract tagged limited
private type; neither can have visible components. A class-wide limited private type
is allowed in a remote access type. Shouldn't a limited interface be allowed?
(2) The definition of remote access types includes any anonymous access types that occur
visibly in the remote types package. But such anonymous access types are necessarily
part of another construct (access discriminants, access parameters, access components);
they will not themselves be used remotely unless the containing construct is. But this
rule makes significant restrictions on which anonymous access types can be used and how.
For instance, an access-to-subprogram parameter is required by this rule to be passed
only remote subprograms, even though the subprogram that is using the parameter is not
itself a remote subprogram.
Should this restriction be relaxed?
(3) Should we formally say that Annex E pragmas have no effect on implementations that
don't support Annex E? Doing so would allow us to declare additional packages to have
Remote_Types pragmas, as we wouldn't have to worry about the effect on most
implementations.
!recommendation
(See Summary.)
!wording
** TBD **
!discussion
The solution requires care, as a non-limited type can be derived from a limited interface
type. That would violate the intent that a remote access type can only designate a limited
object.
Excluding anonymous access types also requires care: if one appears as a component of a
remote type, the remote type ought to be required to have user-defined stream attributes
(that is, any exclusion should not change the rules for external streaming).
-- !corrigendum E.2.2(9/1)
!ACATS Test
!appendix
From: Brad Moore
Sent: Tuesday, June 19, 2007 2:29 AM
I have come across a potential use for interface types that currently is not allowed in Ada 2005,
yet seems like it would be a useful and natural extension to add to the language.
At the very least, it seems worthy of discussion. It seems that this capability could be enabled
by making only minor wording changes to Annex E to relax restrictions for remote access types.
Specifically, it seems useful to be able to specify limited interfaces as remote access types.
However E.2.2(9/1) states:
(9/1) An access type declared in the visible part of a remote types or remote call interface library unit is called
a remote access type.
Such a type shall be
(9.1/1) - an access-to-subprogram type, or
(9.2/1) - a general access type that designates a class-wide limited private type or a class-wide private type extension
all of whose ancestors are either private type extensions or limited private types.
A limited interface cannot be used because of the restriction in (9.2/1) since an interface
is not a private type, even though it would seem to be implicitly private since an
interface type cannot have any visible record components.
eg. The following code excerpt will compile if Client_Buffer_Type is declared as
an abstract tagged limited private type. It does not compile if it declared as
a limited interface type, due to the restriction stated in (9.2/1) above.
package Buffer_Notifications is
pragma Pure;
-- type Client_Buffer_Type is abstract tagged limited private;
type Client_Buffer_Type is limited interface;
procedure Notify
(Buffer_Client : access Client_Buffer_Type;
Data : in String) is abstract;
--private
-- type Client_Buffer_Type is abstract tagged limited null record;
end Buffer_Notifications;
with Buffer_Notifications; use Buffer_Notifications;
package Buffer_Server is
pragma Remote_Call_Interface;
type Buffer_Access is access all Client_Buffer_Type'Class;
procedure Register (Buffer : Buffer_Access);
procedure Send_To_Buffers(Data : String);
No_More_IDs : exception;
end Buffer_Server;
It seems this could be allowed if E.2.2(9.2/1) were modified from;
(9.2/1) - "a general access type that designates a class-wide limited private type or
a class-wide private type extension all of whose ancestors are either
private type extensions or limited private types."
to state;
(9.2/1) "a general access type that designates a class-wide limited interface type or
a class-wide limited private type or a class-wide private type extension all of
whose ancestors are private type extensions, interface types, or limited private types"
Also E.2.2(14/2) would likely need to be modified from;
"The primitive subprograms of the corresponding specific limited private type shall only have
access parameters if they are controlling formal parameters; each non-controlling formal
parameter shall support external streaming (see 13.13.2);"
to something along the lines;
"The primitive subprograms of the corresponding specific limited private type or
limited interface type shall only have access parameters if they are controlling
formal parameters; each non-controlling formal parameter shall support external
streaming (see 13.13.2);"
Hopefully the following questions could be considered in the discussion that might
be generated;
Would this be a change that would be relatively easy for vendors to implement?
Is there a general feeling that this would be a useful capability?
Are there reasons why limited interface types are restricted from being remote access types?
Should an AI be created for this?
****************************************************************
From: Tucker Taft
Sent: Tuesday, June 19, 2007 1:32 PM
I agree with your suggestion that we should probably
allow access to class-wide limited interface as a
remote access type.
One niggling concern is that a non-limited type can be
derived from a limited interface. I am feeling too
slow-witted today to decide whether that is a real
issue.
****************************************************************
From: Brad Moore
Sent: Wednesday, June 20, 2007 11:45 AM
Thanks Tuck, for sharing your niggling concern. I share your concern,
so I have revised my suggested wording changes, because it seems that
the wording I originally suggested allows a private extention that is
derived from a nonlimited interface.
Also, just to clarify, the intent of my suggested revision to
the wording is to not only allow class-wide limited interfaces
as remote access types, but to also allow class-wide
synchronized interfaces, class-wide protected interfaces,
and class-wide task interfaces as remote access types.
Since all of these are limited, I am hoping the wording is
generic enough to include those others as well.
Firstly,
RM 7.3(6/2) defines the notion of a limited private extension,
7.3(6/2) "A private type is limited if its declaration includes the reserved
word limited; a private extension is limited if its ancestor type is a
limited type that is not an interface type,
or if the reserved word limited or synchronized appears in its definition.
If the partial view is nonlimited, then the full view shall be nonlimited.
If a tagged partial view is limited, then the full view shall be limited.
On the other hand, if an untagged partial view is limited, the full view
may be limited or nonlimited."
Also relevant is;
7.3 (8.1/2) "If the reserved word limited appears in a private_extension_declaration,
the ancestor type shall be a limited type. If the reserved word synchronized appears
in a private_extension_declaration, the ancestor type shall be a limited interface."
It seems to help the wording if we speak of limited private extensions, rather than
just private extensions, so I inserted "limited" before "private extension" in my
revised suggested wording. Also, the RM defines "private extension", but does not
define "private type extension", so I removed the word "type".
There are many references to "private extension" throughout the RM, but
"private type extension" only appears in this one paragraph. I presume that there
might be value in making this minor editorial change regardless of whether any other
wording changes are made to 9.2/1.
New suggested wording for E.2.2 (9.2/1);
E.2.2 (9.2/1) "a general access type that designates a class-wide limited interface type
or a class-wide limited private type or a class-wide limited private extension."
The phrase "all of whose ancestors are private type extensions, interface types, or
limited private types" seems redundant to me. If the private extension is limited,
all ancestor private type extensions and private types would also have to be limited.
Is that correct? That is why I also removed that clause. The sentence is now simpler,
but hopefully I haven't removed something that was needed.
I would appreciate any feedback if anyone sees any problems or holes in the proposed
wording. I realize I am probably getting ahead of myself with proposed wording changes,
I am hoping only to suggest that any such wording changes needed for this change would
likely be minimal. More important at this time, would be to get a sense for how others
felt about the usefulness or need for being able to use class-wide limited interface
types as remote access types.
****************************************************************
From: Tucker Taft
Sent: Wednesday, June 20, 2007 2:37 PM
We cannot remove the part about:
" ... all of whose ancestors are private [type] extensions,
interface types, or limited private types"
because we want to rule out the case where a private extension
has a non-private record or record extension as an
ancestor. I agree that removing "type" from
"private type extension" would be more consistent.
For what it's worth, my concern was that the *object*
designated by the access-to-limited-interface'Class
might be non-limited. I'm not sure that there is
any problem with that, but it is something new.
****************************************************************
From: Brad Moore
Sent: Friday, June 22, 2007 1:54 AM
> We cannot remove the part about:
>
> " ... all of whose ancestors are private [type] extensions,
> interface types, or limited private types"
>
> because we want to rule out the case where a private extension
> has a non-private record or record extension as an
> ancestor.
Of course you are right. I was focussing too much on the limitedness
factor, at the expense of the privateness factor.
Also, I now think it is better to move the word "limited" from where I
originally suggested, before "private extension all of whose ancestors..."
to before "interface types" in the clause that we cannot remove.
ie.,
E.2.2 (9.2/1) "a general access type that designates a class-wide limited
interface type or a class-wide limited private type or a class-wide private
extension all of whose ancestors are private extensions,
limited interface types, or limited private types."
That seems to more neatly plug the hole in the wording I originally suggested that
would allow a private extension derived from a non-limited interface to be
used as a remote access type.
> For what it's worth, my concern was that the *object*
> designated by the access-to-limited-interface'Class
> might be non-limited. I'm not sure that there is
> any problem with that, but it is something new.
That is something I hadn't thought of and didn't pick up
from your original reply. I see that now. I also think I see why it's not
easy to know offhand if there is an issue with this or not. It seems quite likely
that there wouldn't be an issue, but requires some more deeper thought
to think it through.
On the surface this limitedness issue seems to be a similar issue
to the corresponding privateness issue. That is, I believe it is possible to
extend a private extension with a record extension, so that the
*object* used in a remote access type could have visible components.
I believe non-private object components would have been allowed in remote
access type objects in Ada 95 also, and that part does not seem to have changed,
so if it wasn't a problem in Ada95, it likely isn't a problem in Ada 2005 either.
The new thing as a result of this suggested change would be that an object used
as a class-wide remote access type could now be non-limited, in addition to possibly
containing non-private components.
The remote "view" of these objects would be that of a limited private type, but the local
"view" could be not as restrictive. The ramification of this would mean that locally,
the object could be copied, or assigned to.
At this point, I don't see a problem with this, but cannot say for sure that there
wouldn't be a problem with this either, or if there may be other issues that I
may have overlooked.
Hmmmmm.
Any thoughts anyone might have on this are appreciated.
****************************************************************
From: Robert A. Duff
Sent: Saturday, June 30, 2007 9:27 AM
There is no pragma Remote_Types in the containers packages
(Ada.Containers.Vectors and friends). Is this an oversight?
Is there some reason why these can't be Remote_Types?
Note that Remote_Types was added after the fact to some Ada 95
packages, such as Ada.Finalization.
****************************************************************
From: Pascal Leroy
Sent: Wednesday, August 1, 2007 2:33 AM
> There is no pragma Remote_Types in the containers packages
> (Ada.Containers.Vectors and friends). Is this an oversight?
> Is there some reason why these can't be Remote_Types?
I see two difficulties with this.
The first difficulty is the streaming of cursors. This is an issue that
we discussed during the design of the containers, and we have rules (e.g.,
A.18.2(88/2)) to the effect that streaming a cursor raises P_E. The
reason is that we could not figure out what sense it makes to stream a
cursor: a cursor typically includes a pointer to a container, and surely
we do not want to stream the associated container when we stream a cursor.
The only alternative that I can think of would be for the cursor to record
some form of network-wide identity of the associated container, but that
seems awfully expensive. And I don't believe that we want to say that
only some types in these library units are remote types.
The second difficulty has to do with remote access types. Remember that
access types declared in the visible part of a Remote_Types package are
remote access types, and are subject to specific rules (see E.2.2). Now
there are a number of anonymous access-to-subprogram types in the visible
part of the containers, and if these types were remote
access-to-subprogram types, you could only pass in remote subprograms.
That seems like an unacceptable burden for the user: they would have to
make all sorts of units RCI for no good reason, and to live with the
associated restrictions. Not to mention that there would probably be a
significant overhead in parameter passing and subprogram calls (unless the
implementation is very smart and detects that the called subprogram is
actually in the same partition).
Overall, I'd say that it would create too much trouble for users and
implementers. If someone really wants to transport containers, they'll do
that explicitly by using the streaming attributes (unlike cursors,
containers can be streamed, of course).
****************************************************************
From: Robert A. Duff
Sent: Wednesday, August 1, 2007 10:01 AM
Hmm -- you're one day too late. ;-) I actually implemented it yesterday.
It was not trivial -- I couldn't just add the Remote_Types pragma all
over the place, because we had some internal implementation packages
that needed to be turned into pragma-Pure, and that required stirring the code
around quite a bit. I haven't checked it into CVS yet...
...
> The first difficulty is the streaming of cursors. This is an issue that
> we discussed during the design of the containers, and we have rules (e.g.,
> A.18.2(88/2)) to the effect that streaming a cursor raises P_E. The
> reason is that we could not figure out what sense it makes to stream a
> cursor: a cursor typically includes a pointer to a container, and surely
> we do not want to stream the associated container when we stream a cursor.
> The only alternative that I can think of would be for the cursor to record
> some form of network-wide identity of the associated container, but that
> seems awfully expensive. And I don't believe that we want to say that
> only some types in these library units are remote types.
I don't buy the first difficulty. Sure, you can't stream cursors, and you get
a run-time error if you try. Shrug.
The goal is to be able to send vectors and mappings and whatnot.
> The second difficulty has to do with remote access types. Remember that
> access types declared in the visible part of a Remote_Types package are
> remote access types, and are subject to specific rules (see E.2.2). Now
> there are a number of anonymous access-to-subprogram types in the visible
> part of the containers, and if these types were remote
> access-to-subprogram types, you could only pass in remote subprograms.
> That seems like an unacceptable burden for the user: they would have to
> make all sorts of units RCI for no good reason, and to live with the
> associated restrictions. Not to mention that there would probably be a
> significant overhead in parameter passing and subprogram calls (unless the
> implementation is very smart and detects that the called subprogram is
> actually in the same partition).
The second, on the other hand, might be a real problem.
Is it really the intent that anonymous access types are remote if they appear
in a Remote_Types package? Are you saying that the following example would be
illegal, if Vectors were Remote_Types, since Process is not a remote procedure?
with Ada.Containers.Vectors; use Ada.Containers;
procedure Example is
package My_Vectors is new Vectors
(Index_Type => Positive, Element_Type => Character);
use My_Vectors;
V : Vector := To_Vector (New_Item => 'A', Length => 10);
procedure Process(Element : in out Character) is
begin
Element := 'x';
end Process;
begin
Update_Element (V, Index => 4, Process => Process'Access);
end Example;
In fact, GNAT does not complain about the above (using my private version that
has pragma Remote_Types in all the Containers packages, except the ones that
are Pure).
****************************************************************
From: Tucker Taft
Sent: Wednesday, August 1, 2007 11:37 AM
Although it needs explicit clarification, I believe
that access parameters and access discriminants should be
permitted without restriction in Remote_Types packages.
I believe "remote access types" are only the *named* access
types declared in the visible part. Similarly, I believe
our various additional sorts of anonymous access types
should be permitted without restriction, except the
existing restriction that all visible types that have
streaming attributes must support external streaming.
On the other hand, in RCI packages, access parameters
have significant restrictions.
It sounds like at a minimum we need an AI to clarify
the rules for anonymous access types and Remote_Types
packages.
****************************************************************
From: Randy Brukardt
Sent: Thursday, August 2, 2007 12:10 AM
...
> > The first difficulty is the streaming of cursors. This is an issue that
> > we discussed during the design of the containers, and we have rules (e.g.,
> > A.18.2(88/2)) to the effect that streaming a cursor raises P_E. The
> > reason is that we could not figure out what sense it makes to stream a
> > cursor: a cursor typically includes a pointer to a container, and surely
> > we do not want to stream the associated container when we stream a
cursor.
>
> I don't buy the first difficulty. Sure, you can't stream cursors, and you get
> a run-time error if you try. Shrug.
The type Cursor violates E.2.2(8/2) in that it doesn't support external
streaming. I realize that the implementation of a containers package in Ada
probably would fool the compiler into thinking it did (because there would
be a user-defined stream attribute), but nothing in the definition of the
description of the containers packages says or implies that these support
external streaming.
> The goal is to be able to send vectors and mappings and whatnot.
You can stream those yourself, and you don't get into trouble with the
construction of the packages if you do so. Ada doesn't allow you do define
*just* those types as remote types (a much more useful definition than
trying to make the entire package remoteable).
****************************************************************
From: Randy Brukardt
Sent: Thursday, August 2, 2007 12:19 AM
> Although it needs explicit clarification, I believe
> that access parameters and access discriminants should be
> permitted without restriction in Remote_Types packages.
> I believe "remote access types" are only the *named* access
> types declared in the visible part. Similarly, I believe
> our various additional sorts of anonymous access types
> should be permitted without restriction, except the
> existing restriction that all visible types that have
> streaming attributes must support external streaming.
"without restriction" is clearly wrong. You surely want the basic
restrictions on remote types to apply to anonymous types used as
components/discriminants (not sure about parameters).
In particular, you do not want to allow:
type Something (D : access Integer) is record
A : Character;
end record;
in a Remote_Types package unless this type has user-defined stream
attributes; it isn't externally streamable without that. And I doubt very
much that we want to repeal that requirement just because there is an access
discriminant.
> On the other hand, in RCI packages, access parameters
> have significant restrictions.
>
> It sounds like at a minimum we need an AI to clarify
> the rules for anonymous access types and Remote_Types
> packages.
I admit that I can't quite figure out what the purpose of Remote_Types
packages are supposed to be. The description seems to imply that having
subprograms in the package doesn't make sense, but that doesn't seem to be
the case in practice. So I can't tell what the rules for anonymous access
parameters ought to be. (Other than that they shouldn't exist in the first
place, but that's a discussion best had over several bottles of wine or
beer. :-)
****************************************************************
From: Robert Dewar
Sent: Thursday, August 2, 2007 6:20 AM
> You can stream those yourself, and you don't get into trouble with the
> construction of the packages if you do so. Ada doesn't allow you do define
> *just* those types as remote types (a much more useful definition than
> trying to make the entire package remoteable).
Streaming them yourself is MUCH less convenient!
****************************************************************
From: Pascal Leroy
Sent: Friday, August 3, 2007 1:59 AM
> Hmm -- you're one day too late. ;-) I actually implemented
> it yesterday. It was not trivial -- I couldn't just add the
> Remote_Types pragma all over the place, because we had some
> internal implementation packages that needed to be turned
> into pragma-Pure, and that required stirring the code around
> quite a bit. I haven't checked it into CVS yet...
This is another reason why I am opposed to making these units
Remote_Types. A Remote_Types unit can only depend on pure, shared passive
or remote type units. This imposes all sorts of restrictions on the
auxiliary units used to implement the containers, notably with respect to
access types. For instance, our implementation uses an auxiliary unit to
manage binary trees. This unit is, of course, full of access types. I
didn't try to see what happens if I slap a categorization pragma on it,
but on the surface things don't look good. In fact having to deal with
pragma Preelaborate all over the place was already a significant pain.
I don't see why we would make everybody's life complicated for an annex
which, as far as I can tell, is only supported by one implementation.
Maybe the solution is to say that the containers are Remote_Types iff the
implementation supports annex E. That couldn't create portability issues:
if you care about annex E, you better use GNAT anyway, so portability is
moot.
At any rate, we'll need to resolve the questions raised by Tuck regarding
anonymous access types.
****************************************************************
From: Robert Dewar
Sent: Friday, August 3, 2007 4:12 PM
> I don't see why we would make everybody's life complicated for an annex
> which, as far as I can tell, is only supported by one implementation.
> Maybe the solution is to say that the containers are Remote_Types iff the
> implementation supports annex E. That couldn't create portability issues:
> if you care about annex E, you better use GNAT anyway, so portability is
> moot.
why not do that for ALL instances of this pragma in the standard libraries?
****************************************************************
From: Robert Dewar
Sent: Friday, August 3, 2007 4:19 PM
> This is another reason why I am opposed to making these units
> Remote_Types. A Remote_Types unit can only depend on pure, shared passive
> or remote type units. This imposes all sorts of restrictions on the
> auxiliary units used to implement the containers, notably with respect to
> access types.
That's an artifact of your implementation, not a language issue (the
language does not say the bodies have to be in Ada). What GNAT does
to deal with MANY such problems in implementing the run time is to
make categorization errors warnings when compiling run time library
files, and then we suppress the warnings where needed (after verifying
as is almost always the case, that the warning is a junk consequence
of the RM rules that in fact does not intefere with the implementation).
In your case you can completely ignore categorization errors from
remote types in implementing your run time, since they are always
junk if you have no Annex E.
> For instance, our implementation uses an auxiliary unit to
> manage binary trees. This unit is, of course, full of access types. I
> didn't try to see what happens if I slap a categorization pragma on it,
> but on the surface things don't look good. In fact having to deal with
> pragma Preelaborate all over the place was already a significant pain.
We just completely eliminated this pain by the approach above, I really
cannot imagine trying to obey the silly Preelaborate categorization
dependency rules in the implementation of the run time (silly because
Preelaborate is a messed up gizmo which tries to be too many things
to too many language features)
> I don't see why we would make everybody's life complicated for an annex
> which, as far as I can tell, is only supported by one implementation.
Equally you don't want to make the containers difficult for users of
this Annex with the implementation that *does* support this Annex.
> Maybe the solution is to say that the containers are Remote_Types iff the
> implementation supports annex E. That couldn't create portability issues:
> if you care about annex E, you better use GNAT anyway, so portability is
> moot.
moot = arguable, undecided, which is not quite what you mean here.
However the proposal certainly seems reasonable. It says that
the Remote_Types pragmas in these units are only there if you
support Annex E, so there is no portability issue anyway. Your
proposal is entirely portable, so I don't understand the claim
that it is moot.
****************************************************************
From: Randy Brukardt
Sent: Saturday, August 4, 2007 9:48 PM
> > This is another reason why I am opposed to making these units
> > Remote_Types. A Remote_Types unit can only depend on pure, shared passive
> > or remote type units. This imposes all sorts of restrictions on the
> > auxiliary units used to implement the containers, notably with respect to
> > access types.
>
> That's an artifact of your implementation, not a language issue (the
> language does not say the bodies have to be in Ada). What GNAT does
> to deal with MANY such problems in implementing the run time is to
> make categorization errors warnings when compiling run time library
> files, and then we suppress the warnings where needed (after verifying
> as is almost always the case, that the warning is a junk consequence
> of the RM rules that in fact does not intefere with the implementation).
I dislike this strategy [which, let me hasen to say, is perfectly legitimate].
I prefer to "eat my own dogfood" -- that is, use the compiler and language as
they were designed. That's especially true for packages like the containers
which are easy to write in pure Ada. If there is something in our compiler
implementation that is causing pain, then it becomes a priority to fix that
in someway (because it is likely to be causing pain to users as well).
Similarly, if there is something in the language that is causing pain,
then that should be a priority to get fixed.
We enforce pure and preelaborate restrictions everywhere we can. Even our
assembler makes a half-hearted attempt to enforce this restrictions (it
doesn't allow library level objects in pure units, for instance).
If it is necessary to end-run around the restrictions of Pure or Preelaborate
to get anything done, then I have to wonder what the value of having it is.
End users will have the same needs to avoid the restrictions, but they don't
have the same ability to do so. [And any ability they do have is a bug in the
language, not a feature.] Which suggests that either the restrictions need
to be revisited (to some extent, we did that this time) or that the whole
idea be dropped.
Getting off of soapbox...
****************************************************************
From: Robert Dewar
Sent: Sunday, August 5, 2007 7:12 AM
> I dislike this strategy [which, let me hasen to say, is perfectly
> legitimate]. I prefer to "eat my own dogfood" -- that is, use the compiler
> and language as they were designed. That's especially true for packages like
> the containers which are easy to write in pure Ada. If there is something in
> our compiler implementation that is causing pain, then it becomes a priority
> to fix that in someway (because it is likely to be causing pain to users as
> well). Similarly, if there is something in the language that is causing
> pain, then that should be a priority to get fixed.
Note that there is an important difference between implementing the
predefined packages and applications programming. In the latter it is
normal and frequent to try to make something preelaborate, and then
find out there is a restriction (perhaps sensible, perhaps junk) that
prevents it. You simply back off in that case (or perhaps when using
GNAT, use pragma Restrictions (No_Elaboration_Code), which is probably
what you wanted anyway).
But in the case of the predefined libraries you can't back off in this
way, so you have to kludge things. No big deal!
> If it is necessary to end-run around the restrictions of Pure or
> Preelaborate to get anything done, then I have to wonder what the value of
> having it is.
Indeed pragma Preleaborate is a seriously messed up feature in my
opinion. It tries to do three things at a time, and does not get
any of them quite right.
****************************************************************
From: Robert Dewar
Sent: Sunday, August 5, 2007 7:12 AM
> I dislike this strategy [which, let me hasen to say, is perfectly
> legitimate]. I prefer to "eat my own dogfood" -- that is, use the compiler
> and language as they were designed. That's especially true for packages like
> the containers which are easy to write in pure Ada. If there is something in
> our compiler implementation that is causing pain, then it becomes a priority
> to fix that in someway (because it is likely to be causing pain to users as
> well). Similarly, if there is something in the language that is causing
> pain, then that should be a priority to get fixed.
Anyway, even if you think this, it is a VERY thin justification for
removing a useful feature from the language ("sorry you can't do that,
not because it is an ill-chosen feature, or not useful, but
because implementing it would offend my aesthetic senses/prefernces").
****************************************************************
From: Robert A. Duff
Sent: Sunday, August 5, 2007 7:45 AM
> I dislike this strategy [which, let me hasen to say, is perfectly
> legitimate]. I prefer to "eat my own dogfood" -- that is, use the compiler
> and language as they were designed. That's especially true for packages like
> the containers which are easy to write in pure Ada.
In most cases, I agree. In fact, I was able to convert the containers to
Remote_Types using pure Ada. I had to change an internal generic package to
pragma-Pure, which required adding "for T'Storage_Size use 0;" on an access
type, which required adding a new access type for allocation, and defining
New_Blah and Free_Blah routines, which do new/U_D, and convert the access type
back and forth, which required adding "all" to the original access type.
That's what I meant by stirring the code around.
It was already the case that the access type was in a unit with types (no
operations), and the operations were in child units, and the children were
with'ed only by bodies of the containers (so these didn't need to be Pure).
On the other hand, if that's too painful, the approach outlined by Robert is
perfectly reasonable. Yes, it suggests that there might be something wrong
with Ada, but..., well..., nobody ever claimed Ada is perfect.
>...If there is something in
> our compiler implementation that is causing pain, then it becomes a priority
> to fix that in someway (because it is likely to be causing pain to users as
> well). Similarly, if there is something in the language that is causing
> pain, then that should be a priority to get fixed.
>
> We enforce pure and preelaborate restrictions everywhere we can. Even our
> assembler makes a half-hearted attempt to enforce this restrictions (it
> doesn't allow library level objects in pure units, for instance).
>
> If it is necessary to end-run around the restrictions of Pure or
> Preelaborate to get anything done, then I have to wonder what the value of
> having it is. End users will have the same needs to avoid the restrictions,
> but they don't have the same ability to do so. [And any ability they do have
> is a bug in the language, not a feature.] Which suggests that either the
> restrictions need to be revisited (to some extent, we did that this time) or
> that the whole idea be dropped.
I'd be in favor of dropping pragma Preelaborate (except for those pesky
"compatibility" concerns...).
> Getting off of soapbox...
;-)
****************************************************************
From: Robert A. Duff
Sent: Sunday, August 5, 2007 7:49 AM
> Maybe the solution is to say that the containers are Remote_Types iff the
> implementation supports annex E.
That seems like a good compromise.
In fact, I think any pragma Remote_Types appearing in the core language has to
be interpreted to be not-really-there if the implementation doesn't claim to
support annex E. That is, you can't write a test case that can tell whether
pragma Remote_Types appears in the Containers packages, without using Annex E
features, so if Annex E doesn't exist, the compiler can ignore any requirements
for Remote_Types.
****************************************************************
From: Pascal Leroy
Sent: Monday, August 6, 2007 6:14 AM
> That's an artifact of your implementation, not a language
> issue (the language does not say the bodies have to be in
> Ada).
The containers were very carefully crafted so that their bodies could be
written in Ada, and in fact there are several pure Ada implementations
around. As far as I am concerned, any request to change the standard in a
way that would make it impossible to write them in Ada is a no-no.
One reason for this is that we wanted to leave open the possibility for
3rd parties (perhaps in the free software community) to develop additional
containers (e.g., synchronized, bounded, etc.) and to be able to do so
without going through insane compiler-dependent drudgery.
Bob tells us that it *is* actually possible to write the containers in Ada
with pragma Remote_Types. Fine. But it would be irresponsible to ignore
the impact on existing implementations: if it is too high, implementers
will just ignore the change.
> (silly because Preelaborate is
> a messed up gizmo which tries to be too many things to too
> many language features)
I couldn't agree more, but this is water under the bridge.
****************************************************************
From: Pascal Leroy
Sent: Monday, August 6, 2007 6:14 AM
> On the other hand, if that's too painful, the approach
> outlined by Robert is perfectly reasonable. Yes, it suggests
> that there might be something wrong with Ada, but...,
> well..., nobody ever claimed Ada is perfect.
It suggest that folks who are not compiler writers cannot develop decent
containers, which sounds very wrong to me.
****************************************************************
From: Robert Dewar
Sent: Monday, August 6, 2007 9:05 AM
All we *might* be saying is that it might not be possible to
do the exact specs in the RM, that's not the same as not being
able to do decent containers. And after all from the point of
view of the distribution folks, decent = remote types present!
Seeing as the language does not allow people to replace the bodies
of Containers UNLESS they are implementors:
> 4 The implementation may restrict the replacement of language-defined
> compilation units. The implementation may restrict children of
> language-defined library units (other than Standard).
So regardless of any discussion of pragmas, you may not be able
to write your own bodies to replace the ones your vendor gives you.
****************************************************************
From: Randy Brukardt
Sent: Monday, August 6, 2007 7:17 PM
> > ... Similarly, if there is something in the language that is causing
> > pain, then that should be a priority to get fixed.
>
> Anyway, even if you think this, it is a VERY thin justification for
> removing a useful feature from the language ("sorry you can't do that,
> not because it is an ill-chosen feature, or not useful, but
> because implementing it would offend my aesthetic senses/prefernces").
I'm not quite sure how you managed to leap from "priority to get fixed" to
"removing a useful feature"; surely, one possible fix would be to remove the
feature but clearly that is the last resort. It would make more sense to try
to eliminate the source of pain, and that is what I meant by the above.
For me, most of my packages could logically have a Preelaborate pragma, but
they can't because (1) they depend on Text_IO or similar I/O packages; (2)
they depend on Calendar or on of the other timing packages; or (3) they
depend on a package that has (1) or (2). I might have more trouble with the
restrictions on the code, but I've never been able to check because I never
get that far.
(There are possible workarounds to (2) and especially (1), but they have
run-time costs that aren't always appropriate.)
Obviously, the best fix would be to reduce the restrictions on Preelaborate
and/or find a substitute for (1) and (2). Dropping the feature altogether
wouldn't be what I would prefer to do; I'd love to be able to use it because
it reduces the code needed at runtime.
****************************************************************
From: Robert Dewar
Sent: Tuesday, August 7, 2007 3:51 AM
...
> For me, most of my packages could logically have a Preelaborate pragma, but
> they can't because (1) they depend on Text_IO or similar I/O packages;
We deal with this by providing an I/O package with a useful subset of
Text_IO capabilities that is Preelaborate.
> Obviously, the best fix would be to reduce the restrictions on Preelaborate
> and/or find a substitute for (1) and (2). Dropping the feature altogether
> wouldn't be what I would prefer to do; I'd love to be able to use it because
> it reduces the code needed at runtime.
In GNAT, if what you are after is eliminating elaboration code, the
preferable way to do it is pragma Restrictions (No_Elaboration_Code) for
two reasons:
1. It is unit by unit
2. pragma Preelaborate does not ensure no elaboration code
****************************************************************
Questions? Ask the ACAA Technical Agent