Version 1.5 of ai05s/ai05-0150-1.txt

Unformatted version of ai05s/ai05-0150-1.txt version 1.5
Other versions for file ai05s/ai05-0150-1.txt

!standard 8.4(4)          10-02-04 AI05-0150-1/03
!standard 8.4(8/2)
!class Amendment 09-04-22
!status work item 09-04-22
!status received 09-04-22
!priority Medium
!difficulty Medium
!subject Use all type clause
!summary
Add "use all type" to provide a more powerful form of use_type_clause.
!problem
There have been complaints that a use type clause does not make enough things visible (e.g. enumeration literals, classwide operations for tagged types), whereas a use_package_clause makes too much visible. Something in between is wanted.
!proposal
Provide a more powerful form of use_type_clause, specified by including the reserved word "all", as in
use all T;
This new form extends the set of declarations whose visibility is modified by a use type clause to include primitive operators of the type and (if the type is tagged) subprograms that operate on T'Class.
!wording
Modify 8.4(4) to add optional "all" reserved word syntax:
use_type_clause ::= use {all} type subtype_mark {, subtype_mark};
Add to the end of 8.4(8/2):
If a use_type_clause whose scope encloses a place includes the reserved word "all", then the following are also potentially use-visible at this place if its declaration is visible at this place:
- Each primitive subprogram of T Redundant[including each enumeration
literal (if any)];
- Each subprogram that is declared immediately within the declarative
region in which an ancestor type of T is declared and that operates on a class-wide type that covers T.
[Editor's note: Steve suggested using "in the same way" avoid having to repeat the three "place" definition. Thus:
If a use_type_clause includes the reserved word "all", then the following are also made potentially use-visible in the same way as the primitive operators of T:
I started wondering exactly what "in the same way" meant, and realized that writing it out was not significantly longer. So I erred on the side of clarity (vs. redundancy, the previous sentence of the paragraph is very similar to the new one). - RLB]
!discussion
The model of "use all type" for tagged type is that it makes the same subprograms that have parameters of the type directly visible that are directly usable in prefix notation. If Obj.Proc is legal for an object of type T, then too will use all type T; Proc(Obj); be legal. "use all type" also makes constructor functions directly visible.
The use of a package use clause introduces a maintenance hazard into a program. Adding a new non-overloadable entity (like an object or subtype) to a package P can make unrelated code that happens to "use" P illegal. That can happen because the non-overloadable entity will "cancel" any other uses of the same identifier, even if they are clearly unrelated (objects of different types, for example). In contrast, overloadable entities only become ambiguous when there is an actual profile conflict.
Since "use all type" only makes overloadable entities visible, it neatly avoids this maintenance hazard.
!example
package P is type Enum is (Aa, Bb, Cc); type T is tagged null record; procedure Proc (X : T'Class; Y : Enum); end P;
with P; package Q is subtype T_Sub is P.T; subtype E_Sub is P.Enum; end Q;
with Q; procedure R is use all type Q.T_Sub; use all type Q.E_Sub; Z : P.T; begin Proc (X => Z, Y => Bb); end R;
--!corrigendum 8.4(4) --!corrigendum 8.4(8/2)
!ACATS test
Add ACATS tests for this new feature.
!appendix

This AI was split from AI05-0135-1; there is a small amount of discussion
on this idea in the volumous e-mail in that AI (mostly at the start).

****************************************************************

From: Robert Dewar
Date: Saturday, June 27, 2009  2:59 PM

[Editor's note: From a thread that starts in AI05-0074-5 and then wanders into
"use clause" territory...]

> People who are "use adverse" may not want to use this "use package"
> thing (for the same reasons they don't use the existing "use"), and
> therefore the feature may not address the instantiation problem for
> all the Ada community, whereas I unable to imagine a reason why people
> would become "special-instantiation adverse".

a) I don't think the language design should pay attention to peculiar
    adverse reactions of this type.

b) I don't think you can possibly guess what strange adverse reactions
    people wil acquire.

Specifically, the use adverse crowd likes to require explicit qualification of
all references, but this principle is badly broken for derived types anyway, so
that object oriented code routinely has references to a variable Clunk with no
explicit declaration of Clunk in sight, even if no use clauses are present. Yes,
there is an implicit declaration and a tool could point you to this implicit
declaration, but once you depend on such tools, the whole motivation for
explicit qualification is dubious if you ask me.

I somewhat share the preference for the "use package" approach, though I do
understand what you are saying (that so far at least this is not as expressive).

****************************************************************

From: Randy Brukardt
Date: Saturday, June 27, 2009  3:31 PM

...
> Specifically, the use adverse crowd likes to require explicit
> qualification of all references, but this principle is badly broken
> for derived types anyway, so that object oriented code routinely has
> references to a variable Clunk with no explicit declaration of Clunk
> in sight, even if no use clauses are present.
> Yes, there is an implicit declaration and a tool could point you to
> this implicit declaration, but once you depend on such tools, the
> whole motivation for explicit qualification is dubious if you ask me.

This was one of the reasons that I was opposed to basing Ada OOP on derived
types in the first place. But that's water under the dam.

One of the real objections to "use" is that it is such a blunt instrument. It's
all or nothing, and you often get lots of stuff you don't want along with the
stuff you do want. We've of course worked on that some; I almost exclusively use
"use type" in new code. Prefix notation for calls helps a lot for OOP stuff, as
well. The proposed "use all type" would probably cover most of the rest of the
cases.

In any case, I don't use a special tool to figure out declarations, but I still
qualify (almost) everything. I just make an educated guess as to where the
inherited Clunk is defined. That's probably easier for me to get right than
most, but it isn't *that* hard. I usually find it harder to determine if there
is an appropriate Clunk available anywhere (Ada likes to make things disappear
for no obvious reason).

My objection to "use package" mainly comes down to problems with maintenance if
you did use qualified references. It seems to make those references no more
stable than used entities, which seems like a step backwards.

In any case, we have a series of problems to address, and I surely hope we can
find solutions to most of them that don't cause too much indigestion.

****************************************************************

From: Bob Duff
Date: Sunday, June 28, 2009  10:15 AM

> The proposed "use all type" would probably cover most of the rest of
> the cases.

I don't much like the "use all type" idea.  You're right that it it covers
"most".  But it doesn't import all related declarations, which is what I want.
For ex., it imports primitive operations of the type, but it doesn't import the
exceptions raised by those operations, which really ought to come along for the
ride.

Packages are all about visibility, so importing based on type rather than
package seems like a kludge to me.

****************************************************************

From: Robert Dewar
Date: Sunday, June 28, 2009  10:32 AM

Me too, I find use type a useless addition to the language :-) And I certainly
don't want to march further down that dead end.

****************************************************************

From: Bob Duff
Date: Sunday, June 28, 2009  10:15 AM

> a) I don't think the language design should pay attention to peculiar
>     adverse reactions of this type.
>
> b) I don't think you can possibly guess what strange adverse reactions
>     people wil acquire.

I agree with Robert.

It's fine with me if use-averse people don't want to use any feature whose
syntax includes 'use', but then they shouldn't complain when they don't get the
benefits of such features (along with the drawbacks, I admit).

> Specifically, the use adverse crowd likes to require explicit
> qualification of all references, but this principle is badly broken
> for derived types anyway, so that object oriented code routinely has
> references to a variable Clunk with no explicit declaration of Clunk
> in sight, even if no use clauses are present.

It is also broken in the case of instantiations.  You end up saying
Instance.Blah, when the actual declaration of Blah is in Some_Generic, which is
far away from Instance.

****************************************************************

From: Robert Dewar
Date: Sunday, June 28, 2009  10:32 AM

> It is also broken in the case of instantiations.  You end up saying
> Instance.Blah, when the actual declaration of Blah is in Some_Generic,
> which is far away from Instance.

True .. of course this doesn't worry me at all, but I always wonder why the
use-adverse crowd doesn't find these holes problematic? :-)

****************************************************************

From: Randy Brukardt
Date: Monday, June 29, 2009  8:51 PM

Well, actually I *do* find all of these instances (pun intended) of implicit
stuff very disturbing. Of course, as a practical matter, programming Ada without
running into any of them is impossible. Thus, I find myself seriously
conflicted, and I probably end up making incoherent arguments, arguing both
sides at once. No matter, I'm going to keep making them. :-)

Instances aren't quite as bad as derived types, as the instance name is in the
fully qualified name (FQN), and the name of the generic is in the instance. So
it is only one extra step to find the actual declaration. For OOP, the
declaration really doesn't tell you anything (any ancestor could be the source
of the routine, and it isn't even clear from the FQN what type caused the
inheritance).

That being said, I admit I don't see how you could have OOP without such
inheritance. That's probably one reason why I've cooled off on OOP in general
(although it surely is useful in some cases).

In any event, I use "use" clauses very rarely, and fully qualify almost
everything, including Ada.Strings.Unbounded.To_Unbounded_String (to give my
least favorite Ada FQN). I doubt that will change: even in the case of implicit
stuff, the FQN shows you where the inheritance and/or instance is, which still
simplifies determining where the actual declaration is.

****************************************************************

From: Robert Dewar
Date: Monday, June 29, 2009  9:21 PM

> That being said, I admit I don't see how you could have OOP without
> such inheritance. That's probably one reason why I've cooled off on
> OOP in general (although it surely is useful in some cases).

Well think of it this way, OO is all about NOT knowing what you are calling, so
it is somewhat incompatible with requiring an explicit mark showing what you are
calling

> In any event, I use "use" clauses very rarely, and fully qualify
> almost everything, including Ada.Strings.Unbounded.To_Unbounded_String
> (to give my least favorite Ada FQN). I doubt that will change: even in
> the case of implicit stuff, the FQN shows you where the inheritance
> and/or instance is, which still simplifies determining where the actual
> declaration is.

I find Ada.Strings.Unbounded.To_Unbounded_String really horrible.
I can't imagine anyone preferring to write this :-). The name
To_Unbounded_String is perfectly adequate, and writing all that qualification
just detracts from readability in my view.

To me, if you want to find out where the declaration is, press a button, if you
don't have software that does that, get some!

****************************************************************

From: Randy Brukardt
Date: Monday, June 29, 2009  9:46 PM

> > That being said, I admit I don't see how you could have OOP without
> > such inheritance. That's probably one reason why I've cooled off on
> > OOP in general (although it surely is useful in some cases).
>
> Well think of it this way, OO is all about NOT knowing what you are
> calling, so it is somewhat incompatible with requiring an explicit
> mark showing what you are calling

Which is probably why I've cooled off on OOP. ;-)

Seriously, I realize this, and that's why the prefix notation is much
preferable; it makes the routines "belong" to the object and there is no
argument about figuring out where they come from.

> > In any event, I use "use" clauses very rarely, and fully qualify
> > almost everything, including
> > Ada.Strings.Unbounded.To_Unbounded_String
> > (to give my least favorite Ada FQN). I doubt that will change: even
> > in the case of implicit stuff, the FQN shows you where the
> > inheritance and/or instance is, which still simplifies determining
> > where the actual declaration is.
>
> I find Ada.Strings.Unbounded.To_Unbounded_String really horrible.
> I can't imagine anyone preferring to write this :-). The name
> To_Unbounded_String is perfectly adequate, and writing all that
> qualification just detracts from readability in my view.

If I need to write a lot of these, I generally rename it to "+".
"To_Unbounded_String" is an abomination no matter how you write it. (It should
really be some sort of user-defined conversion or something else short.) But I
really don't much like the design of this package much anyway (the fact that
proper literals are impossible with it makes it nasty), it's unfortunate that we
are stuck with it for string handling.

> To me, if you want to find out where the declaration is, press a
> button, if you don't have software that does that, get some!

That's not really possible unless I was to change compilers permanently. I don't
have the free time to write such a tool (it would not be easy with the Janus/Ada
compiler front-end). And I know I can't afford your compilers. :-)

****************************************************************

From: Robert Dewar
Date: Tuesday, June 30, 2009  6:41 AM

> If I need to write a lot of these, I generally rename it to "+".
> "To_Unbounded_String" is an abomination no matter how you write it.
> (It should really be some sort of user-defined conversion or something
> else
> short.) But I really don't much like the design of this package much
> anyway (the fact that proper literals are impossible with it makes it
> nasty), it's unfortunate that we are stuck with it for string handling.

I think you are really complaining about the language here, I don't see how the
package could be much more convenient.

I wish we had put in the unary conversion operator that Jean and I argued for (a
single character operator), and then used it for things like
To_Unbounded_String.

The "+" operator works, but enough people find it a kludge that we can't
convince people to use it in RM packages.

>> To me, if you want to find out where the declaration is, press a
>> button, if you don't have software that does that, get some!
>
> That's not really possible unless I was to change compilers permanently.

Well you could always use the GPL version of GNAT as a development tool, the
GNAT environment can be setup to support other compilers conveniently, similar
to the way Rational was used early on for convenient development with final
compilation being done with some other compiler.

Note that to me, this capability of clicking to find a declaration is really
crucial in easy navigation of complex sources where you can't hold all the
declarations in your head. Full qualification is a pale substitute for this
single click.

And it's not as though this is something unique to GNAT, Rational had this kind
of capability years before GNAT did :-) We were playing catch up in the early
years.

The real point here is that sure you can manage without such a tool, but the
great majority of Ada programmers DO have such a tool in their standard toolset
and rely on it. This means two things:

a) you don't want to distort the design of the language because of this
   particular tool limitation. Early on in the design of Ada, we left out square
   brackets because they were not conveniently available in EBCDIC. This
   tradition of exclusion has continued even though the original reason is now
   pretty much 100% bogus.

b) if you write sources for external consumption, it is a pity if they are
   distorted by the lack of this tool.

I can buy an argument that says "I think full qualification reads better because
...". I probably don't agree, but I find it a legitimate argument.

I don't buy an argument that says "I prefer full qualification because I don't
have appropriate tools for dealing with sources that are not fully qualified".

> don't have the free time to write such a tool (it would not be easy
> with the Janus/Ada compiler front-end). And I know I can't afford your
> compilers. :-)

Well you could probably as I say use the GPL version just fine, and you never
know, if you ask AdaCore to provide you full support free for their professional
version, in aid of developing the ACATS suite, they might be happy to oblige (or
ask the same of one of the other companies, like Rational!)

****************************************************************

From: Randy Brukardt
Date: Tuesday, June 30, 2009  1:09 PM

...
> I wish we had put in the unary conversion operator that Jean and I
> argued for (a single character operator), and then used it for things
> like To_Unbounded_String.
>
> The "+" operator works, but enough people find it a kludge that we
> can't convince people to use it in RM packages.

I agree with this. I tried unsuccessfully to resurrect this idea for Ada 2005.

...
> And it's not as though this is something unique to GNAT, Rational had
> this kind of capability years before GNAT did :-) We were playing
> catch up in the early years.

I'm well aware of that; that's how I know the implementation effort it would
take to create such a tool for Janus/Ada. :-)

The problem in our case is that our front-end was designed for batch operation,
and it isn't practical to extract information from the symbol table without
setting up the entire environment first. That would not work well for an
interactive tool. (We have the same problem efficiently implementing ASIS.) I
suspect it would not be as significant a problem on today's machines and perhaps
I need to revisit this issue someday. One could imagine using the debugger
information for this, but that would only work for successfully compiled
programs (as opposed to successfully compiled *units*), which seems to be too
much of a limitation for an editing tool.

Anyway, pretty much off-topic.

...
> > don't have the free time to write such a tool (it would not be easy
> > with the Janus/Ada compiler front-end). And I know I can't afford
> > your compilers. :-)
>
> Well you could probably as I say use the GPL version just fine, and
> you never know, if you ask AdaCore to provide you full support free
> for their professional version, in aid of developing the ACATS suite,
> they might be happy to oblige (or ask the same of one of the other
> companies, like Rational!)

:-) I've tried to avoid using the GNAT Pro version I have for non ACATS work as
I haven't wanted to abuse the provided support. And it's hard to use any tool
for a length of time without running into some issue where you need support.

****************************************************************

From: Brad Moore
Date: Tuesday, June 30, 2009  9:49 AM

> In any event, I use "use" clauses very rarely, and fully qualify
> almost everything, including Ada.Strings.Unbounded.To_Unbounded_String
> (to give my least favorite Ada FQN). I doubt that will change: even in
> the case of implicit stuff, the FQN shows you where the inheritance
> and/or instance is, which still simplifies determining where the actual declaration is.

Our coding standard has the "thou shalt not have a use clause", which came from
whoever it was that made these rules for Ada 83 code. Nobody seemed to question
that rule, which suggests that people at least had an understanding about why
the rule was put in place. When we moved to Ada 95, the "use type" clause did
seem to be an acceptable compromise, however. Lately, I've been thinking that
another way to further relax this draconian rule in a manner that the use
adverse crowd might find acceptable would be to require partly qualified names,
but allow use clauses to eliminate the outermost part of the qualification up to
containing package that contains the name.

eg.

with Interfaces.C; use Interfaces;
X : C.int;

or

with Ada.Containers.Doubly_Linked_Lists;
use Ada.Containers;
package Lists is new Doubly_Linked_Lists(Node);

or

with Ada.Strings.Unbounded;
 use Ada.Strings;
S : Unbounded.Unbounded_String := Unbounded.To_Unbounded_String("Foo");

This seems reasonable, because if you want to find the fully qualified name, you
can find it at the top of the package spec (or package body).

If we want to chip away at the numbers of the use adverse crowd, then I can
think of several restriction pragmas that might convince some to jump ship.

There likely are better names for the restrictions one could come up with, but
hopefully they make sense

1) pragma Restrictions(No_Unqualified_Package_Names);

This would mean that every reference must be at least partly qualified, but
would encourage the dropping of the outermost parts of the qualification as
described above. Programs could freely contain use clauses, so long as every
reference was at least partly qualified.

2) pragma Restrictions(No_Unqualified_Package_Names_If_Withed_Package_Count_Exceeds(N));

This would allow unqualified names if the number of withed packages is small
enough that it should not be too hard to figure out where references come from.
For example, if N = 1, then it's obvious where the reference came from. A Hello
World program that only withs Ada.Text_IO, would be allowed to write
Put_Line("Hello World"); without any qualification (provided that there is a
"use Ada.Text_IO;" clause).

3) pragma Restrictions(No_Unqualified_Package_Names_Other_Than(Name));

This would allow certain packages to be used fully unqualified.
The idea is that you could specify as many packages as you want, (with multiple
uses of this pragma) and this pragma would be compatible with the previous
pragma, but would conflict with the first pragma above. For example, I doubt
there are any Ada programmers who do not know which package contains the
Put_Line subprogram. Similarly, there may be common user defined packages whose
use is so prevalent in a system that it would be acceptable to not have to
qualify everywhere.

Of course, there is nothing stopping these from becoming implementation defined
pragmas supported by a particular vendor, but I think we would want these to be
language defined so that one could count on portability to other vendors and
retain the properties enforced by the pragmas.

Would any of these pragmas be useful or worth defining?

****************************************************************

From: Jean-Pierre Rosen
Date: Tuesday, June 30, 2009  10:23 AM

> 1) pragma Restrictions(No_Unqualified_Package_Names);
> [...]
> 2) pragma
> Restrictions(No_Unqualified_Package_Names_If_Withed_Package_Count_Exce
> eds(N));
> [...]
> 3) pragma Restrictions(No_Unqualified_Package_Names_Other_Than(Name));
> [...]

> Would any of these pragmas be useful or worth defining?

These are great ideas for AdaControl (but see rules Use_Clauses and
Not_Selected_Names). The domain of checks done by the compiler and by external
tool certainly overlap, and the limit is a matter of appreciation (if not of
taste). In this case, I'd put that rather on the tool side, but YMMV.

****************************************************************

From: Brad Moore
Date: Wednesday, July  1, 2009  11:01 AM

> These are great ideas for AdaControl

Glad to hear these might be of use. As I mentioned previously, these pragmas
have greater appeal if they can be ported to multiple vendors and multiple
platforms. Since AdaControl is an ASIS application, I see that in theory it can
provide this portability (to other ASIS supported platforms) through the tool,
without having to be in the language.

> (but see rules Use_Clauses and Not_Selected_Names).

If I understand you correctly, you are suggesting these should be in terms of "expanded name" rather than package name. i.e.
Something like;

1) pragma Restrictions (Only_Expanded_Names);
2) pragma Restrictions
(Only_Expanded_Names_Unless_Withed_Package_Count_Exceeds(N));
3) pragma Restrictions (Only_Expanded_Names_Except_For(Name));

> The domain of checks done by the compiler and by external tool
> certainly overlap, and the limit is a matter of appreciation (if not
> of taste). In this case, I'd put that rather on the tool side, but
> YMMV.

I can see there might be appeal for making these language defined, depending on
what others think. In particular, I was thinking that if we do get the
integrated packages, "use package" feature worked out, then these pragmas might
we worth considering for inclusion in that AI, since they further weaken the
argument about how the integrated package feature might not be of interest to
the use-adverse crowd. As Robert Dewar pointed out however, the use-adverse
crowd argument is already a fairly weak argument. Still, it would be nice if we
can take the wind out of the sails for the argument. One might argue that having
the pragmas checks implemented in AdaControl is good enough to take the wind out
of these sails.

On the other hand... these pragmas would do absolute wonders for our "good
taste"/"bad taste" pragma ratio. :-)

****************************************************************

From: Jean-Pierre Rosen
Date: Wednesday, July  1, 2009  12:16 PM

> If I understand you correctly, you are suggesting these should be in
> terms of "expanded name" rather than package name. i.e.
> Something like;
>
> 1) pragma Restrictions (Only_Expanded_Names);
> 2) pragma Restrictions
> (Only_Expanded_Names_Unless_Withed_Package_Count_Exceeds(N));
> 3) pragma Restrictions (Only_Expanded_Names_Except_For(Name));

I was not suggesting anything, I just pointed at existing AdaControl rules that
are more or less in that direction. Use_Clauses controls all use clauses, except
for specified packages; Not_Selected_Names require that certain identifiers be
always qualified names (typically "instance", so you have to write
"My_Abstraction.Instance"). The latter could easily be extanded to cover all
names.

****************************************************************

From: Brad Moore
Date: Wednesday, July  1, 2009  3:11 PM

> I was not suggesting anything, I just pointed at existing AdaControl
> rules that are more or less in that direction.

Ah, now I understand your comment. I thought you were pointing me at RM rules,
not AdaControl rules. I couldn't find Not_Selected_Names, but assumed that was a
typo, and you meant to say Selected Names. The only thing I found there that
might be related was Expanded Name, which seemed like a better choice than
Package Name, since it is a defined term. So my misinterpretation of your
comment happened to lead me to a place that generated another comment.
Fascinating.

Also, I find it rather fascinating that a pragma Restriction could actually end
up giving you freedom. (Freedom to use use clauses) though it restricts you in
another area.

****************************************************************

From: Robert Dewar
Date: Wednesday, July  1, 2009  3:04 PM

> These are great ideas for AdaControl (but see rules Use_Clauses and
> Not_Selected_Names). The domain of checks done by the compiler and by
> external tool certainly overlap, and the limit is a matter of
> appreciation (if not of taste). In this case, I'd put that rather on
> the tool side, but YMMV.

I agree, they seem like coding standard rules to me, and we would be more
inclined to put them in gnatcheck (our version of a checking tool, similar to
JPR's AdaControl).

****************************************************************


Questions? Ask the ACAA Technical Agent