!standard 13.12.1(3/2) 11-02-11 AI05-0242-1/01 !class Amendment 11-02-11 !status work item 11-02-11 !status received 11-02-09 !priority Low !difficulty Easy !subject No_Implementation_Units restriction !summary A new restriction is defined: pragma Restrictions(No_Implementation_Units); !problem Implementations are allowed to add implementation-defined units as descendants of the standard packages, and users can do so as well. For instance, it is not uncommon for implementations to provide additional containers packages as children of Ada.Containers. It can be confusing as to whether these units are language-defined. This is important when creating portable code, as implementation-defined units are unlikely to be available on other implementations. !proposal (See wording.) !wording Add after 13.12.1(3/2): No_Implementation_Units There is no mention in the context_clause of any implementation-defined descendants of packages Ada, Interfaces, or System. This restriction applies only to the current compilation or environment, not the entire partition. !discussion (See proposal.) !example pragma Restrictions(No_Implementation_Units); !ACATS test Add a ACATS B test for this feature. !appendix From: Robert Dewar Sent: Monday, July 26, 2010 7:46 PM Implementations are allowed to add grandchildren to Ada etc. And GNAT takes advantage of this, e.g. to add the encoding packages to earlier versions of Ada. But this creates portability problems, we should really have a restriction to prevent this, in the style of No_Implementation_Pragmas. How about No_Implementation_Units ? I am not really suggesting a new AI at this stage, just some guidance on whether this is a good idea so that implementations can adopt it (and then we can put it into Ada 2019 :-)) **************************************************************** From: Tucker Taft Sent: Monday, July 26, 2010 8:14 PM This sounds like a very good idea. Users are often confused about what packages are "standard" Ada and what are not. Does this also cover System.* and Interfaces.*? One rule might be to disallow any package that starts with "Ada", "System", or "Interfaces" that is not in the reference manual. These are the ones that confuse users. **************************************************************** From: Robert Dewar Sent: Monday, July 26, 2010 8:33 PM Right, that's what I had in mind. And the idea would be in particular to forbid use of RM packages in an inappropriately earlier version of Ada (e.g. using the string encoding packages in Ada 2005 mode). Of course I know that can't be part of the standard, but that would be the encouraged usage (and is what GNAT intends to do). **************************************************************** From: Randy Brukardt Sent: Thursday, February 10, 2011 1:01 AM A vaguely related suggestion from back in July: Robert Dewar has suggested: How about {a restriction} No_Implementation_Units? Tucker suggested: One rule might be to disallow any package that starts with "Ada", "System", or "Interfaces" that is not in the reference manual. These are the ones that confuse users. I was thinking that we could address this in this AI as well (I filed the mail that way). I realize it would have helped if I had told Bob that at some point. :-) Anyway, are there any objections to this idea?? (If there are any, we'll have to do it as a separate AI.) **************************************************************** From: Robert Dewar Sent: Thursday, February 10, 2011 5:23 AM > One rule might be to disallow any package that starts with "Ada", > "System", or "Interfaces" that is not in the reference manual. These > are the ones that confuse users. Yes, that's my intention exactly for this restriction **************************************************************** From: Dan Eilers Sent: Thursday, February 10, 2011 11:35 AM > One rule might be to disallow any package that starts with "Ada", > "System", or "Interfaces" that is not in the reference manual. These > are the ones that confuse users. There is a related issue of disallowing implementation-dependent indentifiers declared in package System, such as System.Max_Priority. **************************************************************** From: Tucker Taft Sent: Thursday, February 10, 2011 11:53 AM Good point. These are also sources of non-portability. In this case, I presume the restriction would be on *use* of such an identifier, since you probably don't expect there to be a version of System just sitting around that omits these things. Perhaps "pragma Restrictions(Pristine);"? ;-) **************************************************************** From: Bob Duff Sent: Thursday, February 10, 2011 1:48 PM > A vaguely related suggestion from back in July: Very vaguely. ;-) > Robert Dewar has suggested: > > How about {a restriction} No_Implementation_Units? > > Tucker suggested: > > One rule might be to disallow any package that starts with "Ada", > "System", or "Interfaces" that is not in the reference manual. These > are the ones that confuse users. > > I was thinking that we could address this in this AI as well (I filed > the mail that way). I realize it would have helped if I had told Bob > that at some point. :-) No need to tell me -- I saw those e-mails in AI05-0153-3. I deliberately left out No_Implementation_Units, because Robert's e-mail seemed to make it clear that he's not asking for a standard feature. He's asking for an informal agreement that folks would implement this restriction. He wrote: I am not really suggesting a new AI at this stage, just some guidance on whether this is a good idea so that implementations can adopt it (and then we can put it into Ada 2019 :-)) > Anyway, are there any objections to this idea?? (If there are any, > we'll have to do it as a separate AI.) I'm opposed to putting this feature in the standard at this time. It just doesn't seem worth the trouble, and it doesn't seem particularly related to aspects. But I don't feel strongly about it, and if it goes in, I'd be happy to put it in this AI. Dan Eilers wrote: > There is a related issue of disallowing implementation-dependent > indentifiers declared in package System, such as System.Max_Priority. And Tucker Taft replied: > Good point. These are also sources of non-portability. > In this case, I presume the restriction would be on > *use* of such an identifier, since you probably don't expect there to > be a version of System just sitting around that omits these things. > > Perhaps "pragma Restrictions(Pristine);"? ;-) This goes way, way too far, in my opinion. Ada just has way to many potential non-portabilities. I mean, any use of Integer is potentially non-portable, and you can't use String without Integer. A from-scratch language design could do much better (see Java), but it's too late for Ada. Please stop inventing new "nice to have" features! **************************************************************** From: Robert Dewar Sent: Thursday, February 10, 2011 6:29 PM > This goes way, way too far, in my opinion. Ada just has way to many > potential non-portabilities. I mean, any use of Integer is > potentially non-portable, and you can't use String without Integer. A > from-scratch language design could do much better (see Java), but it's too late for Ada. wrt integer, Ada is as portable as Java, Ada Integer means 32 bits on any platform supporting Java (care to find a realistic counter example?) **************************************************************** From: Robert Dewar Sent: Thursday, February 10, 2011 6:47 PM I believe Randy's compiler for Windows has 16-bit Integer. He can correct me if I'm wrong. And some Ada compilers do Integer arithmetic (intermediate results) in 64 bits. Java is more portable, in that it requires a particular wrong answer on "overflow". ;-) And if you don't buy the Integer example, try Long_Integer -- gcc/gnat has both 32-bit and 64-bit versions (which caused me a big headache when helping to port it to 64-bit Windows!). Anyway, so what? My point is I don't want to go tracking down all the potential non-portabilities, and then have to argue about whether Integer'Last is more or less portable than Priority'Last. **************************************************************** From: Randy Brukardt Sent: Thursday, February 10, 2011 6:53 PM All Intel-based versions of Janus/Ada have always had Integer as a 16-bit type; that originally was to keep the binary files created by the various Janus/Ada compilers intercompatible (this was in the Ada 83 days, before streams). A related issue was far too much use of "Integer" to mean 16-bits in the runtime (most of that has been squeezed out in the intervening years). It would be easy enough to change (essentially, change the definition of Standard and recompile everything), but even now, a lot of Sequential_IO and Direct_IO files would be incompatible. I've wanted to make this switchable with a command line switch, but that turns out to be a lot harder to accomplish. In any case, it provides a fine test for supposely portable Ada code: probably 75% of it fails to run on Janus/Ada because it has assumed a range for Integer. Using a properly declared type fixes that. **************************************************************** From: Robert Dewar Sent: Thursday, February 10, 2011 6:58 PM > All Intel-based versions of Janus/Ada have always had Integer as a > 16-bit type; that originally was to keep the binary files created by > the various Janus/Ada compilers intercompatible (this was in the Ada > 83 days, before streams). A related issue was far too much use of > "Integer" to mean 16-bits in the runtime (most of that has been > squeezed out in the intervening years). Right, but these days that is just not viable in an Ada compiler, so I regard this as an oddity from the past. Limiting strings to 32K bytes is simply not a viable choice on any modern architecture. So in practice Integer will always be 32 bits on any reasonable modern architecture. **************************************************************** From: Dan Eilers Sent: Thursday, February 10, 2011 7:05 PM > Anyway, so what? My point is I don't want to go tracking down all the > potential non-portabilities, and then have to argue about whether > Integer'Last is more or less portable than Priority'Last. Just so there's no confusion here, I wasn't referring to "Priority'Last" being non-portable (even though it will differ between implementations). I was referring to System.Max_Priority, which is not defined by the language, but apparently is added by GNAT. This isn't just a hypothetical potential problem. A week or two ago, Brad Moore stumbled into this exact problem when he posted his "Paraffin" code, which unintentionally used System.Max_Priority rather than Priority'Last. Given that portability is a major goal of Ada, I think that the easy-to-fix portability problems deserve serious consideration, even if hard-to-fix problems remain. **************************************************************** From: Randy Brukardt Sent: Thursday, February 10, 2011 7:10 PM ... > No need to tell me -- I saw those e-mails in AI05-0153-3. > > I deliberately left out No_Implementation_Units, because Robert's > e-mail seemed to make it clear that he's not asking for a standard > feature. He's asking for an informal agreement that folks would > implement this restriction. Robert doesn't have to ask for "informal agreement". He just has to do it, and the rest of us will have to copy him. ;-) In any case, this seems to me like an odd omission from the existing No_Implementation_xxx restrictions, and since we are adding a bunch of other restrictions, we should fix this clear omission. If nobody else agrees, that's fine with me. > > Anyway, are there any objections to this idea?? (If there are any, > > we'll have to do it as a separate AI.) > > I'm opposed to putting this feature in the standard at this time. > It just doesn't seem worth the trouble, and it doesn't seem > particularly related to aspects. > > But I don't feel strongly about it, and if it goes in, I'd be happy to > put it in this AI. OK, but I don't see how we can decide here whether it is in or out; so I think I'll just make a separate AI and you can vote against it if you like. > Dan Eilers wrote: > > > There is a related issue of disallowing implementation-dependent > > indentifiers declared in package System, such as System.Max_Priority. > > And Tucker Taft replied: > > > Good point. These are also sources of non-portability. > > In this case, I presume the restriction would be on > > *use* of such an identifier, since you probably don't expect there > > to be a version of System just sitting around that omits these things. > > > > Perhaps "pragma Restrictions(Pristine);"? ;-) > > This goes way, way too far, in my opinion. Ada just has way to many > potential non-portabilities. I mean, any use of Integer is > potentially non-portable, and you can't use String without Integer. A > from-scratch language design could do much better (see Java), but it's > too late for Ada. I agree with Bob in this case. When you use anything from package System (or package Standard or package Interfaces for that matter), you are taking a level of non-portability. If you want to avoid that non-portability, use pragma No_Dependence. No new features are needed for that. > Please stop inventing new "nice to have" features! I don't even believe that this is a "nice to have" feature. System's contents are inherently non-portable. Using it in the first place means that you want to do something at a low level. Expecting more than that makes no sense. To take a particular example, type Address in the 16-bit x86 versions of Janus/Ada is a record type with Segment and Offset components. Since Ada 83 doesn't have any Address constructor at all, the only way to set an Address value is to initialize it with an aggregate. (If we had done an Ada 95 compiler for that system, we would have done some sort of mapping from Integer_Address, but that would be even less portable). Indeed, most of our 32-bit x86 versions of Janus/Ada used a 48-bit version of Address (again with segment and offset parts), since that matches the actual hardware capabilities. (A lot of malware could have been avoiding if Windows had put the code and data into different segments!!) We eventually had to get of that on Windows because of problems with the segment registers getting clobbered by foreign code. Anyway, my point is that System is inherently system-dependent. It wouldn't be usable without some level of that; I don't see any value to picking out particular things in that package and saying they should be called out by a restriction. **************************************************************** From: Dan Eilers Sent: Thursday, February 10, 2011 7:58 PM > I don't even believe that this is a "nice to have" feature. System's > contents are inherently non-portable. Using it in the first place > means that you want to do something at a low level. Expecting more > than that makes no sense. Actually, people intending write fully portable Ada code end up unwittingly using System.Max_Priority. See the ChameneosRedux benchmark program at: http://shootout.alioth.debian.org/u32/program.php?test=chameneosredux&lang=gnat It says: -- Fully portable : -- No machine/OS dependency -- No dependency of GNAT-compiler specific features and then does: procedure ChameneosRedux is pragma Priority (System.Max_Priority); **************************************************************** From: Tucker Taft Sent: Thursday, February 10, 2011 8:13 PM I suspect that if you suggest a reasonable name for the restriction, GNAT folks might add support for it. Something like: pragma Restrictions(No_Nonstandard_System_Components); I don't really agree with Randy, since often the reason to use things in System is specifically to achieve portability, such as using System.Max_Int, or System.Default_Bit_Order. So it can be annoying that there are seemingly useful declarations in package System that are in fact not standard, and there is no obvious way of realizing that without actually doing a line-by-line comparison with the version of System in the reference manual. **************************************************************** From: Randy Brukardt Sent: Thursday, February 10, 2011 8:40 PM > and then does: > > procedure ChameneosRedux is > pragma Priority (System.Max_Priority); Sure, but so what? 90% of the supposedly "portable" code that I've seen has some compiler dependency. The only code that doesn't have been compiled and debugged on multiple compilers, and there is very little than that. Most such code depends on GNAT features, of course, but it works just as well in the reverse: most of my "portable" code has proven to have some Janus/Ada dependency when compiled with GNAT or ObjectAda. I cannot imagine any way to even come close to banning all of these incompatibilities via a restriction. The biggest problem porting to/from Janus/Ada is the 16-bittedness of type Integer, but there is no restriction to handle that. And if you had one to fix that, there would be plenty of other issues. Including ones of source representation (which no restriction could ever have an impact on). In any case, the use of System is inherently non-portable. The program cited above immediately left the realm of portable code simply by using System. (Dependence on priorities is non-portable for instance; there is no reason to assume a compiler supports more than one, and in that case you do not need any Priority pragmas.) **************************************************************** From: Randy Brukardt Sent: Thursday, February 10, 2011 8:51 PM ... > I don't really agree with Randy, since often the reason to use things > in System is specifically to achieve portability, such as using > System.Max_Int, or System.Default_Bit_Order. > So it can be annoying that there are seemingly useful declarations in > package System that are in fact not standard, and there is no obvious > way of realizing that without actually doing a line-by-line comparison > with the version of System in the reference manual. Dependence on the things defined by the standard is just as likely to cause non-portabilities. (The obvious example being the number of bits in Integer, but it applies to virtually everything in System.) The form of specifying an address (as a number, or a record, or whatever) is clearly not portable (unless the compiler follows the implementation advice and supports none, but even then, the interpretation of Integer_Address is implementation-defined). Unless the restriction plugged most of these things, it is just providing false hope. The only Ada code that can be considered portable is that compiled and tested on more than one Ada compiler. It is quite unlikely that such things would survive such a gauntlet (and even then, they do). [Keep in mind that we made Claw run on 5 different compilers; it takes quite a concerted effort, even when the code was constructed to be portable from the beginning.] It is interesting that this discussion has convinced me that the No_Implementation_xxx restrictions are a waste of time, because they don't do anything significant toward making Ada code portable. So now I'm leaning Bob's way on this one. **************************************************************** From: Tucker Taft Sent: Thursday, February 10, 2011 9:42 PM I think you are taking a narrow view of this. Apparently your experience is different from mine in this area. I find it very annoying when people unintentionally use features of a compiler that are non-standard, thereby making it harder to reuse their code, especially when there is an equivalent standard way of doing things. For example, using 'Unrestricted_Access when 'Unchecked_Access (or even 'Access) would have worked fine. Similarly, using Max_Priority rather than Priority'Last. That is really the purpose of these restrictions: to catch unintentional uses of non-standard features, be they attributes, pragmas, units, elements of package Standard, etc. It doesn't suddenly make your program portable, but it does help to reduce the number of *unnecessary* non-portabilities. **************************************************************** From: Randy Brukardt Sent: Thursday, February 10, 2011 10:06 PM But this is an endless slippery slope of restrictions. First the obvious ones, then you add restrictions for non-standard additions to System, then about non-standard additions to other packages (there are several that allow that), then any dependence on the contents of the Implementation packages of the Queue containers, then on non-required types in Standard (Long_Integer, etc.), then on Standard.Integer itself, then ... To do this right, you'd need a restriction for everything that is marked unspecified or implementation-defined in the Standard. Annex M has a list of more than 140 implementation-defined items. And then there is implementation advice, unspecified, and the rest. Are we going to add restrictions to cover all of them? And a significant number of these things can't even be checked at compile-time. And then the question is whether people really are going to use all of these restrictions. That seems doubtful as well. We could, I suppose, wrap all of these restrictions into a profile, but that doesn't really help the implementation cost of having to deal with so many restrictions. (I'm unconvinced that restrictions are the best way to handle this in any case.) So I don't buy it. I'm drawing the line at No_Implementation_Units, and I won't complain if it goes nowhere as well. ****************************************************************