!standard 6.1(19) 12-01-21 AC95-00223/00 !class Amendment 12-01-21 !status received no action 11-01-21 !status received 11-09-19 !subject New attribute 'Default !summary !appendix From: Martin Dowie Sent: Monday, September 19, 2011 6:03 AM I've recently come across a problem which required numerous subprograms to do something different if the default value of a parameter was passed. The best solution I could find was to declare a set of constants that were then used in both the subprogram declaration and within the body of the subprogram but this was rather annoying due to the large number of constants having to be declared. It would have been much cleaner had Ada had an attribute that returned the default value of any parameter, e.g. procedure Demo (P : Integer := 10) is begin if P = P'Default then -- P'Default would return 10 in this case -- Do something when default selected else -- Do something different end if; end Demo; 'Default_Expression might be a better name. The compiler would easily be able to identify when 'Default(_Expression) was used when there wasn't an actual value specified. *************************************************************** From: Adam Beneschan Sent: Monday, September 19, 2011 2:45 PM And if a parameter default expression contains a function call that doesn't necessarily return the same result every time it's called? package Pack1 is function Counter return Integer; procedure Demo (P : Integer := Counter); end Pack1; package body Pack1 is Current_Counter : Integer := 1; function Counter return Integer is Result : Integer; begin Result := Current_Counter; Current_Counter := Current_Counter + 1; return Result; end Counter; procedure Demo (P : Integer := Counter) is begin if P = P'Default then ... end if; end Demo; end Pack1; What are your proposed semantics for this attribute, and how would they work in this case? *************************************************************** From: Martin Dowie Sent: Monday, September 19, 2011 3:26 PM Don't support it - static defaults only. *************************************************************** From: Pascal Sent: Monday, September 19, 2011 3:01 PM Hello. Maybe with attribute Default or whatever returning Boolean True when no actual arg is present in the call for the concerned parameter: procedure Demo (P : Integer := Counter) is begin if P'Default then -- true if call to Demo without actual arg for P ... end if; end Demo; *************************************************************** From: Randy Brukardt Sent: Monday, September 19, 2011 3:40 PM That would require passing a bit-map with every call as to whether or not the parameter is defaulted. Since the compiler cannot in general know what is in the body of a subprogram (because of separate compilation), that would apply to *all* calls of subprograms that have parameters with default expressions. I think that would be way too much run-time overhead for a feature of marginal value, especially as overloading can be used to get the same effect without the run-time overhead. The original proposal doesn't have this problem (although Adam pointed out a problem with it as well). *************************************************************** From: Riccardo Bernardini Sent: Monday, September 19, 2011 4:00 PM I agree that the feature can be in most of cases replaced with overloading, but the overhead it does not seem excessive. Maybe I am missing something, but would not it suffice to just "push" a constant value on the stack? A 32-bit integer has enough room for 32 parameters with default, which suffices (I think) for most cases of interest, so the resulting overhead would be a push and 4 bytes. (Of course, I am thinking about x86-like architectures, maybe things can be different in other cases). If you are in a case where this overhead is not acceptable, one could define another pragma like No_Default_Attribute to turn off this feature (selectively or globally). > The original proposal doesn't have this problem (although Adam pointed out a > problem with it as well). The original it has also the advantage that you can use the actual default value in expressions P'Default * 2 (although I cannot imagine where this could be useful). *************************************************************** From: Randy Brukardt Sent: Monday, September 19, 2011 4:26 PM ... > I agree that the feature can be in most of cases replaced with overloading, > but the overhead it does not seem excessive. Maybe I am missing something, > but would not it suffice to just "push" a constant value on the stack? > A 32-bit integer has enough room for 32 parameters with default, which suffices > (I think) for most cases of interest, so the resulting overhead would > be a push and 4 bytes. (Of course, I am thinking about x86-like architectures, > maybe things can be different in other cases). If you are in a case > where this overhead is not acceptable, one could define another pragma > like No_Default_Attribute to turn off this feature (selectively or globally). It's not acceptable because it is on *all* calls, not just the rare few that use this attribute. And a large part of the execution time of an Ada program is taken up by making calls. Specifically, for Janus/Ada on an x86, a call of a two parameter subprogram requires pushing 4 32 words onto the stack (2 parameters, the return address, and the display value. Adding a fifth word would make such a call 20% slower! I cannot imagine how this feature could possibly be worth making calls 20% slower. Also note that this would make such calls slower compared to other languages (like C). And it would also add overhead to exported subprograms (for which the information could not be accurate anyway). All-in-all, I would guess that this feature alone would make Ada programs 5-10% slower (by default, at least). It would have to be a *lot* more valuable than this one is to have such an impact. > The original it has also the advantage that you can use the actual > default value in expressions P'Default * 2 (although I cannot imagine > where this could be useful). I thought that was the point of the original proposal: if Some_Param = Some_Param'Default then ... Surely equality is an expression! This second proposal doesn't actually tell you the default value, and as Steve Baird pointed out privately, that can be different for different calls (a rename can change defaults). OTOH, the original proposal isn't well-defined because of the renaming issue, so I don't see it being viable, either. *************************************************************** From: Adam Beneschan Sent: Monday, September 19, 2011 7:14 PM ... > Maybe with attribute Default or whatever returning Boolean True when > no = actual arg is present in the call for the concerned parameter: > > procedure Demo (P : Integer := Counter) is > begin > if P'Default then -- true if call to Demo without actual arg for P > ... > end if; > end Demo; The biggest problem there is that since, at the time a call to Demo is seen, the body of Demo may not have been compiled, the compiler can't know whether 'Default is used on any or all of the parameters. This means that every subprogram that has any default parameter would have to take an additional hidden Boolean parameter to indicate whether the parameter is actually present in the call; thus, every subprogram call becomes a little bit slower even if 'Default isn't used anywhere in the program. I believe this is "distributed overhead" that the language designers try to avoid. If there's just one parameter with a default, the simple solution seems to be to overload it: procedure Demo; procedure Demo (P : Integer); where the bodies of both routines are wrappers for some other routine that takes a Boolean parameter indicating whether P is present. I do stuff like this all the time. However, I can understand that this could get unwieldy if there are, say, three parameters with default expressions. If we want a 'Default boolean attribute, perhaps we need a way to specify that information about whether a parameter is defaulted should be passed: procedure Demo (P : Integer := ) with Default_Indication(P) => True; Or some syntax like that. Then P'Default would be allowed only if there's an aspect clause like this enabling the use of 'Default. That would avoid distributed overhead. *************************************************************** From: Steve Baird Sent: Monday, September 19, 2011 7:49 PM > Maybe with attribute Default or whatever returning Boolean True when no > actual arg is present in the call for the concerned parameter: > > procedure Demo (P : Integer := Counter) is > begin > if P'Default then -- true if call to Demo without actual arg for P > ... > end if; > end Demo; 1) Which default are we talking about? There are lots of ways to call a given subprogram which can each introduce a new set of parameter defaults: - by calling a rename of the given subprogram - by calling a generic formal subprogram where the given subprogram is the corresponding actual subprogram - by calling an access to subp value which designates the given subprogram - by making a dispatching call to a subprogram which ends up executing the body of the given subprogram For example, in a case like procedure P (X : Integer := 111); procedure Q (Y : Integer := 222) renames P; procedure P (X : Integer := 111) is begin if X'Defaulted then -- is it ok to assume that X = 111 here? ... end if; end P; begin Q; , what is the value of X'Defaulted in the if-statement? If the answer is anything other than "ignore all defaults except those given with the original subp declaration", then this would impose distributed overhead. Even subprograms which don't declare defaulted parameter values would have to cope with the case where they are passed defaulted actual parameters. So let's assume the answer is "ignore all defaults except those given with the original subp declaration". Even this leads to implementation complexity involving wrappers, assuming that support for this attribute involves some change in the calling conventions for the subprogram in question (e.g., the addition of a parameter as outlined in Riccardo Bernardini's message). Taking the access attribute of a subprogram which has a defaulted parameter would require generating a wrapper routine. The situation with primitive operations of tagged types would be peculiar - an implementation would need to put a wrapper in the dispatch table while keeping the unwrapped version around for use in nondispatching calls. So much for the equivalence of dispatching and nondispatching calls. Which leads to my second point = 2) Replacing a defaulted parameter value with a semantically equivalent explicit value should be a semantics-preserving transformation. This could come up, for example, in a case like transforming if Flag then P1 (17 parameters, letting the 18th default to 0); else P2 (the same 17 parameters, Last_Parameteter => 0); end if; into My_Access_to_Subp_Type'(if Flag then P1'Access else P2'Access).all (the same 17 parameters, Last_Parameteter => 0); Or perhaps in introducing a generic with a formal subprogram in order to factor out a bunch of almost-common code which differs in that one instance calls Foo where another instance calls Bar. We don't want people shying away from such transformations because they can't see the body of some subprogram and they are worried about breaking something. We want to make semantics-preserving transformations easier, not harder. We don't want to increase the number of potential tripwires that someone maintaining a large body of unfamiliar code has to worry about tripping over. *************************************************************** From: Adam Beneschan Sent: Monday, September 19, 2011 8:45 PM > 2) Replacing a defaulted parameter value with a semantically > equivalent explicit value should be a semantics-preserving > transformation. Yes, this makes sense to me. If you want subprograms that behave differently depending on whether a parameter is present or not, then what you really want is either (a) two different subprograms, which could be overloaded subprograms with the same name, or not; or (b) some sort of "optional parameter" feature that isn't part of Ada, although I suppose that if we were influenced by a few too many beers we might be able to design a new syntax like procedure Demo (P : Integer := <>); along with the syntax for the body to determine whether the optional parameter really was missing. Whatever design for this feature that we came up with, I'm sure we'd regret it in the morning. *************************************************************** From: Randy Brukardt Sent: Monday, September 19, 2011 10:26 PM I think it would take quite a few beers (hopefully something like Capitol Blonde Dopplebock or Chimay Trappist Ale or maybe even Rochfort 10 :-). But in any case, it is pretty clear this is a bad idea, and anyway this is not what Martin asked for. The more interesting question is whether what Martin asked for is feasible. Two problems have been noted: (1) Which default? Renames and the like can change the expression. (2) Default expressions that have different answers when re-evaluated. Answering (1) as "the defaults from the original subprogram definition", and (2) as "re-evaluate each time" (and don't do that if it hurts :-) would probably be the easiest and most logical answers. [For (2), default expressions are always re-evaluated when they appear in parameter lists, it would be odd to do anything else for this attribute.] So the remaining question is whether the feature would be sufficiently useful for the effort to implement it. *************************************************************** From: Georg Bauhaus Sent: Tuesday, September 20, 2011 5:00 AM > The more interesting question is whether what Martin asked for is feasible. From a stylistic point of view, I understand that Ada chooses such that whenever you have a name in your hand (visibly) to be passed somewhere, then always use that, even later, not something available indirectly, like 'Default would be, in a sense. This is the case with generics such as Ada.Containers.* that don't re-export the formal Element_Type. You wouldn't need it where the actual for Element_Type is visible. (It would also be "more anonymous" than the actual actual.) Isn't the static value visible in this sense in Martin Dowie's original profile? Explicit constants global to procedure Demo would seem less burdensome if their names convey meaning (a meaning not typically inherent in numeric literals). *************************************************************** From: Bob Duff Sent: Tuesday, September 20, 2011 9:45 AM > Answering (1) as "the defaults from the original subprogram > definition", and > (2) as "re-evaluate each time" (and don't do that if it hurts :-) > would probably be the easiest and most logical answers. Reasonable. Or for (2), say 'Default is legal only if the default is a static expression. Normally, I don't like such rules, but in this case, I don't see any use for 'Default unless it IS static. >...So the remaining > question is whether the feature would be sufficiently useful for the >effort to implement it. My opinion: certainly not. *************************************************************** From: Steve Baird Sent: Tuesday, September 20, 2011 10:52 AM >> ...So the remaining >> question is whether the feature would be sufficiently useful for the >> effort to implement it. > > My opinion: certainly not. I agree. The "workaround" of declaring a constant (perhaps one whose name differs from the desired attribute only in the substitution of an underscore for an apostrophe) seems fine to me. For example X_Default : constant T := <>; procedure Foo (X : T := X_Default) is begin if X = X_Default then ... end Foo; *************************************************************** From: Martin Dowie Sent: Tuesday, September 20, 2011 10:59 AM > I agree. The "workaround" of declaring a constant (perhaps one whose > name differs from the desired attribute only in the substitution of an > underscore for an apostrophe) seems fine to me. It's ok until you have 200 operations, each with maybe 5 defaulted values... :-( *************************************************************** From: Randy Brukardt Sent: Tuesday, September 20, 2011 1:20 PM I have to admit, I'm dubious about this "problem". (I realize that criticizing other people's designs without much information is treading on rather thin ice, but that's never stopped me before, so here goes... :-) It seems to me to be an abuse of the idea of default parameters to care specially about the default value. The whole idea is that this is a normal value that doesn't require special treatment. It's probably better to use overloading (and no default) if special treatment is needed. I can't recall a single instance in Claw (which has hundreds, perhaps thousands of defaults) where we had to test for the default value. (There are some cases where we had to test the parameter value - especially for Boolean parameters - but that has nothing to do with the default.) There are a number of cases where we used overloading when the absence of a parameter requires different behavior. I can imagine that this would happen occasionally, but it doesn't seem to make sense to happen very often, and as the workaround is pretty easy, there doesn't seem to be a real need for a special feature. (Yes, the workaround requires more typing for the extra declaration. Nothing new about that; Ada always requires more typing than other languages [in order to get more explicitness]. If that's a real problem, you're using the wrong language [or wrong IDE/Editor] - go use Forth or Lisp. :-) *************************************************************** From: Riccardo Bernardni Sent: Tuesday, September 20, 2011 1:31 PM Why not APL? (sorry, couldn't resist :-) *************************************************************** From: Gautier de Montmollin Sent: Tuesday, September 20, 2011 2:29 PM > It's ok until you have 200 operations, each with maybe 5 defaulted > values... :-( Why not having a 6th parameter in front of the 5 other ones: use_defaults: Boolean:= True; ? And/or wrapping some parameters into records, in case you have several default values at the same time ? It seems like there is something that can be worked out in the code, before adding something more to the language... Do you have an example you could post to illustrate the problem ? *************************************************************** From: Martin Dowie Sent: Wednesday, September 21, 2011 3:06 AM Would need a Boolean per parameter (as passing control parameter) - not a flier. Also means the user has to know and check if the value they have is the default (what I'd the default changed?). *************************************************************** From: Martin Dowie Sent: Wednesday, September 21, 2011 3:20 AM > I have to admit, I'm dubious about this "problem". > > (I realize that criticizing other people's designs without much > information is treading on rather thin ice, but that's never stopped > me before, so here goes... :-) :-) The 'requirement' is to write a thick Ada binding to a 3rd party's command line interface (the one with ~200 commands!) - so using another language would be a no-no! I have competing requirements, as we'd like this new suite of packages to be user friendly going forward to develop more Ada apps on top (hence defaults for the 99% of the calls that will ever be made but still having the same options as the low level commands available). Competing against that is the requirement to produce the same commands out the back-end as our current (and working) app does - never underestimate how important 'working' is! And the working app doesn't include values that are 'default' in the 3rd parties command line. I agree it's a fairly unusual case (20+ years of Ada and I can't remember thinking I've needed such an attribute before). But it seemed like a trivial addition and if you don't ask, you don't get! (or "shy bairns don't get sweeties" as we'd say in these parts) *************************************************************** From: Randy Brukardt Sent: Wednesday, September 21, 2011 12:38 PM > The 'requirement' is to write a thick Ada binding to a 3rd party's > command line interface (the one with ~200 commands!) > - so using another language would be a no-no! > > I have competing requirements, as we'd like this new suite of packages > to be user friendly going forward to develop more Ada apps on top > (hence defaults for the 99% of the calls that will ever be made but > still having the same options as the low level commands available). > > Competing against that is the requirement to produce the same commands > out the back-end as our current (and working) app does - never > underestimate how important 'working' is! And the working app doesn't > include values that are 'default' in the 3rd parties command line. Thanks for the explanation. It sounds like you have a requirement to abuse default parameters. :-) I can remember some(s) case where I specially handled the output of some routine to avoid giving parameters if the value matched their 3rd-party default. I think that was in order to keep the commands as short as possible, there was some bound on the length and I wanted to avoid reaching that if possible. (Possibly that was in the CVS interface, one version of which runs on Ada-auth.org.) That's fairly similar to your requirement (mine wasn't a big R requirement, but it was valuable, and might have become a big R requirement had I NOT done it right away). But in that case, the defaults that you are interested in are those used by the 3rd-party program, not the ones used in the Ada source. Those *could* be the same, but there is no reason for that to be the case (and I recall that it wasn't the case all of the time in my interface, I used the defaults that were most useful to Ada code; your situation appears to be similar). So it seems to me that you would be better off putting the default values directly into the code with suitable comments (I didn't even use constants, because I was treating the 3rd-party interface as unchanging -- maybe a bad choice), rather than assuming some correspondence between the defaults in the Ada context and in the 3rd-party context. Of course if you do that, you couldn't use the attribute even if it existed. > I agree it's a fairly unusual case (20+ years of Ada and I can't > remember thinking I've needed such an attribute before). But it seemed > like a trivial addition and if you don't ask, you don't get! (or "shy > bairns don't get sweeties" > as we'd say in these parts) Which is the other problem. The need seems to be pretty rare, and since the definition is nowhere near as trivial as it originally appears (Steve has been privately sending me additional issues involving the defaults for inherited routines - it's scary how his mind works...:-), it seems like more trouble than it would be worth. *************************************************************** From: Martin Dowie Sent: Thursday, September 22, 2011 6:19 AM >Thanks for the explanation. It sounds like you have a requirement to >abuse default parameters. :-) > >[snip] > >Of course if you do that, you couldn't use the attribute even if it >existed. Which is where I am now and I need to finish this sooner rather than later, so I'm just living with the extra constants. >Which is the other problem. The need seems to be pretty rare, and since >the definition is nowhere near as trivial as it originally appears >(Steve has been privately sending me additional issues involving the >defaults for inherited routines - it's scary how his mind works...:-), >it seems like more trouble than it would be worth. Fairly enough *************************************************************** From: Gautier de Montmollin Sent: Thursday, September 22, 2011 7:15 AM > The 'requirement' is to write a thick Ada binding to a 3rd party's command > line interface (the one with ~200 commands!) - so using another language would > be a no-no! OK. In the CLI, if you are passing explicitly a value which coincides with the default value, does it have the same effect as letting the parameter blank and having the default value used ? (just wondering why you need to test the value being the default one and make a special case). ***************************************************************