!standard 8.4(4) 10-02-04 AI05-0150-1/03 !standard 8.4(8/2) !class Amendment 09-04-22 !status Amendment 2012 10-04-02 !status ARG Approved 6-1-3 10-02-26 !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 Replace 8.4(4) with the following 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 entities are also potentially use-visible at this place if the declaration of the entity 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 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) @drepl @xcode<@fa@ft<@b>@fa< subtype_mark {, subtype_mark};>> @dby @xcode<@fa@ft<@b>@fa< [>@ft<@b>@fa<] >@ft<@b>@fa< subtype_mark {, subtype_mark};>> !corrigendum 8.4(8/2) @drepl For each package named in of a @fa whose scope encloses a place, each declaration that occurs immediately within the declarative region of the package is @i at this place if the declaration is visible at this place. For each type @i or @i'Class named in a @fa whose scope encloses a place, the declaration of each primitive operator of type @i is potentially use-visible at this place if its declaration is visible at this place. @dby For each package named in of a @fa whose scope encloses a place, each declaration that occurs immediately within the declarative region of the package is @i at this place if the declaration is visible at this place. For each type @i or @i'Class named in a @fa whose scope encloses a place, the declaration of each primitive operator of type @i is potentially use-visible at this place if its declaration is visible at this place. If a @fa whose scope encloses a place includes the reserved word @b, then the following entities are also potentially use-visible at this place if the declaration of the entity is visible at this place: @xbullet including each enumeration literal (if any);> @xbullet is declared and that operates on a class-wide type that covers @i.> !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). ****************************************************************