!standard 3.3.1(11) 11-05-05 AI05-0228-1/05 !standard 3.3.1(13) !standard 3.3.1(21) !standard 3.5(56/2) !standard 3.6(22/2) !standard 6.4.1(13) !standard 13.13.2(35/2) !class Amendment 10-10-22 !status Amendment 2012 11-03-11 !status ARG Approved 7-0-0 11-02-19 !status work item 10-10-22 !status received 10-10-22 !priority Medium !difficulty Easy !subject Default initial values for scalar and array types !summary Two new aspects are added to provide default initial values for scalar types and arrays of scalar types. !problem The new predicate (see AI05-0153-3) and invariant (see AI05-0146-1) aspects provide unreliable results for objects that are not initialized. This can be prevented when a default initial value is provided. It is easy to provide a default initial value for record types, and access types have one defined by the language, but for other kinds of types, it is impossible. This seems bizarre, given that implementations have the capability of doing default initialization (as for record and access types). !proposal Add an aspect Default_Value that can be used on all scalar types, and an additional aspect Default_Component_Value that can be used on all array of scalar types. !wording Add a new bullet after 3.3.1(11): * The implicit initial value for a scalar subtype that has the Default_Value aspect specified is the value of that aspect converted to the nominal subtype (which might raise Constraint_Error - see 4.6, “Type Conversions”); AARM Ramification: This is a dynamic semantics rule, so the visibility of the aspect specification is not relevant -- if the full type for a private type has the Default_Value aspect specified, partial views of the type also have this implicit initial value. Modify 3.3.1(13): * For a (definite) composite subtype, the implicit initial value of each component with a default_expression is obtained by evaluation of this expression and conversion to the component's nominal subtype (which might raise Constraint_Error [- see 4.6, "Type Conversions"]), unless the component is a discriminant of a constrained subtype (the previous case), or is in an excluded variant (see 3.8.1). For each component that does not have a default_expression, {if the composite subtype has the Default_Component_Value aspect specified, the implicit initial value is the value of that aspect converted to the component's nominal subtype; otherwise, } any implicit initial values are those determined by the component's nominal subtype. [Editor's note: We delete the cross-reference because it has been moved into the new bullet; we don't repeat cross-references in paragraphs that will be read together.] Modify 3.3.1(21): There is no implicit initial value defined for a scalar subtype{ unless the Default_Value aspect has been specified for the type}. In the absence of an explicit initialization{ or the specification of the Default_Value aspect}, a newly created scalar object might have a value that does not belong to its subtype (see 13.9.1 and H.1). Add after 3.5(56/2): Static Semantics For a scalar type, the following language-defined representation aspect may be specified with an aspect_specification: Default_Value This aspect shall be specified by a static expression, and that expression shall be explicit, even if the aspect has a boolean type. Default_Value shall be specified only on a full_type_declaration. AARM Reason: The part about requiring an explicit expression is to disallow omitting the value for this aspect, which would otherwise be allowed by the rules of 13.3.1. This is a representation aspect in order to disallow specifying it on a derived type that has inherited primitive subprograms; that is necessary as the sizes of *out* parameters could be different whether or not a Default_Value is specified (see 6.4.1). End AARM Reason. If a derived type with no primitive subprograms inherits a boolean Default_Value aspect, the aspect may be specified to have any value for the derived type. AARM Reason: This is to override the 13.3.1 rule that says that a boolean aspect with a value True cannot be changed. Name Resolution The expected type for the expression specified for the Default_Value aspect is the type defined by the full_type_declaration on which it appears. Add after 3.6(22/2): Static Semantics For an array type with a scalar component type, the following language-defined representation aspect may be specified with an aspect_specification: Default_Component_Value This aspect shall be specified by a static expression, and that expression shall be explicit, even if the aspect has a boolean type. Default_Component_Value shall be specified only on a full_type_declaration. AARM Reason: The part about requiring an explicit expression is to disallow omitting the value for this aspect, which would otherwise be allowed by the rules of 13.3.1. If a derived type with no primitive subprograms inherits a boolean Default_Value aspect, the aspect may be specified to have any value for the derived type. AARM Reason: This is to override the 13.3.1 rule that says that a boolean aspect with a value True cannot be changed for a derived type. Name Resolution The expected type for the expression specified for the Default_Component_Value aspect is the component type of the array type defined by the full_type_declaration on which it appears. Add a new bullet after 6.4.1(13): [Note that 6.4.1(13) was modified by AI05-0196-1 -- we echo that wording here, not the original wording.] * For a scalar type that has the Default_Value aspect specified, the formal parameter is initialized from the value of the actual, without checking that the value satisfies any constraint; AARM Reason: This preserves the language design principle that all objects of a type with an implicit initial value are initialized. This is important so that a programmer can guarantee that all objects of a scalar type have a valid value with a carefully chosen Default_Value. AARM Implementation Note: This rule means that *out* parameters of a subtype T with a specified Default_Value need to be large enough to support any possible value of the base type of T. In contrast, a type that does not have a Default_Value only need support the size of the subtype (since no values are passed in). [Editor's note: We don't need to modify the composite rule, as the changed definition of "implicit initial values" effectively changes this rule to include arrays with a specified Default_Component_Value.] Modify AARM 6.4.1(15.a): This case covers scalar types {that do not have Default_Value specified}, and composite types whose subcomponent's subtypes do not have any implicit initial values. The view conversion for composite types ensures that if the lengths don't match between an actual and a formal array parameter, the Constraint_Error is raised before the call, rather than after. Modify 13.13.2(35/2): In the default implementation of Read and Input for a composite type, for each scalar component that is a discriminant or [whose component_declaration includes a default_expression]{that has an implicit initial value}, a check is made that the value returned by Read for the component belongs to its subtype. Constraint_Error is raised if this check fails. For other scalar components, no check is made. For each component that is of an access type, if the implementation can detect that the value returned by Read for the component is not a value of its subtype, Constraint_Error is raised. If the value is not a value of its subtype and this error is not detected, the component has an abnormal value, and erroneous execution can result (see 13.9.1). In the default implementation of Read for a composite type with defaulted discriminants, if the actual parameter of Read is constrained, a check is made that the discriminants read from the stream are equal to those of the actual parameter. Constraint_Error is raised if this check fails. AARM To Be Honest: An implementation should always be able to detect the error for a null value read into an access subtype with a null exclusion; the "if the implementation can detect" is intended to cover non-null access values. AARM Ramification: A scalar component can have an implicit initial value if it has a default_expression, if the component's type has the Default_Value aspect specified, or if the component is that of an array type that has the Default_Component_Value aspect specified. !discussion It is important that the default initial value be something that makes sense for the type. Simply initializing everything to zero is just as likely to cover bugs as eliminate them. However, if a type has a value specifically that means "Unknown" or "Undefined", it makes perfect sense to initialize all objects to that value. That would greatly reduce the chances of invalid objects of the type existing. We considered making these subtype aspects rather than type aspects. That would allow giving different default values to different subtypes. However, given the existence of many ways to create anonymous subtypes it would be very hard to guarantee that all values of a type are initialized. Without that guarantee, these aspects lose a lot of their purpose. !examples Providing a default initial value for an enumeration type with an unknown value: type Item_State is (Unknown, Fooey, Blarch, ...) with Default_Value => Unknown; Providing string type that is initialized with blanks: type Blank_String is array (Positive range <>) of Character with Default_Component_Value => ' '; !corrigendum 3.3.1(11) @dinsa @xbullet @dinst @xbullet !corrigendum 3.3.1(13) @drepl For a (definite) composite subtype, the implicit initial value of each component with a @fa is obtained by evaluation of this expression and conversion to the component's nominal subtype (which might raise Constraint_Error @emdash see 4.6, "Type Conversions"), unless the component is a discriminant of a constrained subtype (the previous case), or is in an excluded @fa (see 3.8.1). For each component that does not have a @fa, any implicit initial values are those determined by the component's nominal subtype. @dby For a (definite) composite subtype, the implicit initial value of each component with a @fa is obtained by evaluation of this expression and conversion to the component's nominal subtype (which might raise Constraint_Error), unless the component is a discriminant of a constrained subtype (the previous case), or is in an excluded @fa (see 3.8.1). For each component that does not have a @fa, if the composite subtype has the Default_Component_Value aspect specified, the implicit initial value is the value of that aspect converted to the component's nominal subtype; otherwise, any implicit initial values are those determined by the component's nominal subtype. !corrigendum 3.3.1(21) @drepl There is no implicit initial value defined for a scalar subtype. In the absence of an explicit initialization, a newly created scalar object might have a value that does not belong to its subtype (see 13.9.1 and H.1). @dby There is no implicit initial value defined for a scalar subtype unless the Default_Value aspect has been specified for the type. In the absence of an explicit initialization or the specification of the Default_Value aspect, a newly created scalar object might have a value that does not belong to its subtype (see 13.9.1 and H.1). !corrigendum 3.5(56/2) @dinsa An implementation may extend the Wide_Wide_Value, Wide_Value, Value, Wide_Wide_Image, Wide_Image, and Image attributes of a floating point type to support special values such as infinities and NaNs. @dinss @s8<@i> For a scalar type, the following language-defined representation aspect may be specified with an @fa (see 13.1.1): @xhang<@xterm This aspect shall be specified by a static expression, and that expression shall be explicit, even if the aspect has a boolean type. Default_Value shall be specified only on a @fa.> If a derived type with no primitive subprograms inherits a boolean Default_Value aspect, the aspect may be specified to have any value for the derived type. @s8<@i> The expected type for the @fa specified for the Default_Value aspect is the type defined by the @fa on which it appears. !corrigendum 3.6(22) @dinsa The elaboration of a @fa that does not contain any per-object expressions creates the discrete subtype, and consists of the elaboration of the @fa or the evaluation of the @fa. The elaboration of a @fa that contains one or more per-object expressions is defined in 3.8. The elaboration of a @fa in an @fa consists of the elaboration of the @fa or @fa. The elaboration of any @fas and the elaboration of the @fa are performed in an arbitrary order. @dinss @s8<@i> For an array type with a scalar component type, the following language-defined representation aspect may be specified with an @fa (see 13.1.1): @xhang<@xterm This aspect shall be specified by a static expression, and that expression shall be explicit, even if the aspect has a boolean type. Default_Component_Value shall be specified only on a @fa.> If a derived type with no primitive subprograms inherits a boolean Default_Component_Value aspect, the aspect may be specified to have any value for the derived type. @s8<@i> The expected type for the @fa specified for the Default_Component_Value aspect is the component type of the array type defined by the @fa on which it appears. !corrigendum 6.4.1(13) @dinsa For an access type, the formal parameter is initialized from the value of the actual, without a constraint check; @dinst For a scalar type that has the Default_Value aspect specified, the formal parameter is initialized from the value of the actual, without checking that the value satisfies any constraint; !corrigendum 13.13.2(35) @drepl In the default implementation of Read and Input for a composite type, for each scalar component that is a discriminant or whose @fa includes a @fa, a check is made that the value returned by Read for the component belongs to its subtype. Constraint_Error is raised if this check fails. For other scalar components, no check is made. For each component that is of an access type, if the implementation can detect that the value returned by Read for the component is not a value of its subtype, Constraint_Error is raised. If the value is not a value of its subtype and this error is not detected, the component has an abnormal value, and erroneous execution can result (see 13.9.1). In the default implementation of Read for a composite type with defaulted discriminants, if the actual parameter of Read is constrained, a check is made that the discriminants read from the stream are equal to those of the actual parameter. Constraint_Error is raised if this check fails. @dby In the default implementation of Read and Input for a composite type, for each scalar component that is a discriminant or that has an implicit initial value, a check is made that the value returned by Read for the component belongs to its subtype. Constraint_Error is raised if this check fails. For other scalar components, no check is made. For each component that is of an access type, if the implementation can detect that the value returned by Read for the component is not a value of its subtype, Constraint_Error is raised. If the value is not a value of its subtype and this error is not detected, the component has an abnormal value, and erroneous execution can result (see 13.9.1). In the default implementation of Read for a composite type with defaulted discriminants, if the actual parameter of Read is constrained, a check is made that the discriminants read from the stream are equal to those of the actual parameter. Constraint_Error is raised if this check fails. !ACATS test ACATS tests would be needed for this aspect. !appendix [Editor's note: This thread forked off of a discussion of predicates.] From: Robert Dewar Sent: Wednesday, October 13, 2010 11:21 AM > Well, yeah. We get a lot of support calls about uninit vars. > Too bad there's no language feature to prevent those bugs. All language features that "fix" uninitialized variables are evil. Requiring default initialization or providing default implicit initialization are particularly evil in my view. **************************************************************** From: Bob Duff Sent: Wednesday, October 13, 2010 12:33 PM > All language features that "fix" uninitialized variables are evil. I won't touch that with a barge pole. ;-) Anyway, it's irrelevant to my point, which is that uninit vars are a loophole in constraints, so the argument "predicates must be loophole-free, because constraints are" is bogus. >... Requiring default initialization or providing default implicit >initialization are particularly evil in my view. I certainly agree with that. Too bad JDI didn't (I'm talking about access types). **************************************************************** From: Tucker Taft Sent: Wednesday, October 13, 2010 1:01 PM >> ... Requiring default initialization or providing default implicit >> initialization are particularly evil in my view. > > I certainly agree with that. > > Too bad JDI didn't (I'm talking about access types). The default initial value of "null" for an access type seems OK, since you get an exception if you try to use it as though it had a usable non-null value. It is a default initial value of zero that is dangerous, since it is not distinguishable from a "true" initial value of zero. If there were a "null" value for all types, which corresponded roughly to a floating point signaling NaN, that would be fine in my view. You would get notified if you tried to do anything that presumed the object had an "intentional" initial value. **************************************************************** From: Randy Brukardt Sent: Wednesday, October 13, 2010 1:50 PM Right. The annoying thing is that Ada doesn't have a way to set a default initial value for scalar and array types, for those cases where there is an "obviously" bad value. For instance, many of my enumeration types have an value of "unknown" or something like that. It's purpose is exactly to provide a value for those cases where something has gone wrong or nothing has been calculated yet. Typically, it would be used (manually of course) as a default initial value for objects; it would be nice to be able to force all objects to start with that value rather than random garbage. Ada compilers clearly have the mechanism to deal with default initializations (because of access types and record components), so it is annoying that the programmer can't use that when it is appropriate. **************************************************************** From: Robert Dewar Sent: Wednesday, October 13, 2010 5:29 PM TW, on the IM 7040, there was a great instruction intended only for system diagnostics to set parity wrong on a specified word. WATFor fortran used this to initialize all uninitialized variables (under some option flag). And you got a parity error if you tried to load the value. BTW, I don't think it is worth spending too much time on different checking modes. Compilers will likely provide different checking modes anyway, whatever the standard says. **************************************************************** From: Robert Dewar Sent: Wednesday, October 13, 2010 5:27 PM >> It is a default initial value of zero that is dangerous, since it is >> not distinguishable from a "true" initial value of zero. If there >> were a "null" value for all types, which corresponded roughly to a >> floating point signaling NaN, that would be fine in my view. You >> would get notified if you tried to do anything that presumed the >> object had an "intentional" initial value. Big overhead in the array case having to check, and the trouble is that you MUST be able to have 32 tc integers, represented in the obvious way. It would be a menace if Ada insisted on stealing one value. > Ada > compilers clearly have the mechanism to deal with default > initializations (because of access types and record components), so it > is annoying that the programmer can't use that when it is appropriate. Good point, I think I will invent a pragma. In fact the obvious pragma to extend is pragma Initialize_Scalars; and allow the usage pragma Initialize_Scalars (local_type_NAME); 20 minutes work to allow this! **************************************************************** From: Randy Brukardt Sent: Wednesday, October 13, 2010 5:44 PM > >> It is a default initial value of zero that is dangerous, since it > >> is not distinguishable from a "true" initial value of zero. If > >> there were a "null" value for all types, which corresponded roughly > >> to a floating point signaling NaN, that would be fine in my view. > >> You would get notified if you tried to do anything that presumed > >> the object had an "intentional" initial value. > > Big overhead in the array case having to check, and the trouble is > that you MUST be able to have 32 tc integers, represented in the > obvious way. It would be a menace if Ada insisted on stealing one > value. I agree that it doesn't make sense to do it in all cases; it's just odd to not have the capability when it is useful. [That's Tucker's quote, BTW.] > > Ada > > compilers clearly have the mechanism to deal with default > > initializations (because of access types and record components), so > > it is annoying that the programmer can't use that when it is appropriate. > > Good point, I think I will invent a pragma. In fact the obvious pragma > to extend is > > pragma Initialize_Scalars; > > and allow the usage > > pragma Initialize_Scalars (local_type_NAME); > > 20 minutes work to allow this! At one point, someone suggested having an aspect for this purpose. That would look something like: type Item_State is (Unknown, Fooey, Blarch, ...) with Default_Initial_Value => Unknown; This seems like a good use for an aspect, given that it isn't something that ought to be dependent on the view of the type (or subtype, if we wanted to allow that). The (minor) advantage of the aspect over the pragma is that it allows the default value to be specified; that might be helpful if the "Unknown" value is not the first one in the enumeration. **************************************************************** From: Robert Dewar Sent: Wednesday, October 13, 2010 6:00 PM Well we could allow a default value for Initialize_Scalars or some other pragma. IS in GNAT is not always the lowest value, and can in fact be changed at link time or even execution time (the idea is to try different initial values and see if has an observable effect A disadvantage of an aspect if that is the only mechanism is that it is restricted to Ada 2012 mode. We have a lot of customers still stuck at Ada 95 (partly because of the high level of incompatibility between Ada 95 and Ada 2005). **************************************************************** From: Tucker Taft Sent: Wednesday, October 13, 2010 6:10 PM I believe we already discussed something along these lines in the recent ARG meeting. Didn't we invent an aspect spec like "with Default => blah"? Or am I dreaming that? **************************************************************** From: Randy Brukardt Sent: Wednesday, October 13, 2010 6:37 PM I think we invented it, but I don't think anyone took ownership of it and got it added to the agenda. As such, it is now too late (it wasn't included in the scope approved by WG 9), unless someone can figure out a reason why we need to add it for one of the existing AIs. **************************************************************** From: Robert Dewar Sent: Wednesday, October 13, 2010 6:47 PM Sounds good to me, I think I will implement the aspect and the corresponding pragma, so it really doesn't matter too much if it gets into the standard. It's a good idea! **************************************************************** From: Jean-Pierre Rosen Sent: Thursday, October 14, 2010 3:48 AM I was about to suggest an aspect too, but Randy shot first... > A disadvantage of an aspect if that is the only mechanism is that it > is restricted to Ada 2012 mode. We have a lot of customers still stuck > at Ada 95 (partly because of the high level of incompatibility between > Ada 95 and Ada 2005). OTOH, people will move to the new versions if the benefits balance the disagreements. Providing nice features in the most recent modes is a way to push them. **************************************************************** From: Robert Dewar Sent: Thursday, October 14, 2010 6:13 PM Well in fact in GNAT we systematically provide pragmas to match all aspects in any case, the way the internal implementation of aspects work is to translate to the corresponding pragma or attribute definition clause. So for example, we now have pragma predicate and pragma invariant in GNAT. We are more in the business of providing useful features to people than pushing them to use the latest version of Ada. As I say, the biggest barrier is the rather fierce upwards incompatibility of Ada 2005, this has resulted in a barrier for several large users (the issue with return of limited stuff). We have talked about a mode which would provide Ada 95 + all compatible features, but this is quite a bit of work. **************************************************************** From: Robert Dewar Sent: Monday, November 22, 2010 6:17 PM I am not sure I understand the restriction to full type declarations, it seems quite reasonable (and of course trivially implementable) to have a different default value for a derived type, and that may be quite reasonable when the derived type has a range. Oh well, don't really mind much, but in either case, the question arises of whether subtypes inherit these aspects (yes of course, though this may result in invalid values). Do derived types inherit these aspects (I would think yes, especially if you can't specify it on the derived type). **************************************************************** From: Steve Baird Sent: Monday, November 22, 2010 6:27 PM > I am not sure I understand the restriction to full type declarations, > it seems quite reasonable (and of course trivially implementable) to > have a different default value for a derived type, and that may be > quite reasonable when the derived type has a range. A full_type_declaration does not exclude a derived type. I think the AI permits specifying the Default_Initial_Value aspect of a derived scalar type. **************************************************************** From: Randy Brukardt Sent: Monday, November 22, 2010 6:38 PM > I am not sure I understand the restriction to full type declarations, > it seems quite reasonable (and of course trivially implementable) to > have a different default value for a derived type, and that may be > quite reasonable when the derived type has a range. I don't understand this comment. A derived type is a full type declaration (specifically, a derived_type_definition is a kind of type_definition, and 3.2.1(3) says that a full type declaration includes all kinds of type definitions. Here we simply mean that you can't specify this on partial or incomplete views (which are not full type declarations). > Oh well, don't really mind much, > > but in either case, the question arises of whether subtypes inherit > these aspects (yes of course, though this may result in invalid > values). Yes, of course. Even the type can have an invalid value: type Small_Int is range 0 .. 99 with Default_Value => -1; > Do derived types inherit these aspects (I would think yes, especially > if you can't specify it on the derived type). We answer that with the standard rules for inheritance of aspects. However, we need to decide if this is representational or operational to answer that, and then if the latter we still need to define it. So I think this is a valid question, but the answer should clearly be yes. (Why not??) **************************************************************** From: Robert Dewar Sent: Monday, November 22, 2010 7:04 PM > A full_type_declaration does not exclude a derived type. Yes of course, my mistake > I think the AI permits specifying the > Default_Initial_Value aspect of a derived scalar type. So the restriction is the usual one, that we can only specify this for a first subtype, which is fine. **************************************************************** From: Tucker Taft Sent: Monday, November 22, 2010 7:32 PM > I am not sure I understand the restriction to full type declarations, > it seems quite reasonable (and of course trivially implementable) to > have a different default value for a derived type, and that may be > quite reasonable when the derived type has a range. I believe we intended to allow this on a derived type. A derived type declaration is still a "full" type declaration. > Oh well, don't really mind much, > > but in either case, the question arises of whether subtypes inherit > these aspects (yes of course, though this may result in invalid > values). I don't follow here. If the value is outside the subtype, then that is like a null-excluding access type. You have to explicitly initialize it or you get a constraint_error. I don't see how you end up with an invalid value. > > Do derived types inherit these aspects (I would think yes, especially > if you can't specify it on the derived type). I would certainly expect derived types to inherit the "Default_Value" aspect. **************************************************************** From: Robert Dewar Sent: Monday, November 22, 2010 7:37 PM > I believe we intended to allow this on a derived type. A derived type > declaration is still a "full" type declaration. Indeed, this is just my silly mistake >> >> Oh well, don't really mind much, >> >> but in either case, the question arises of whether subtypes inherit >> these aspects (yes of course, though this may result in invalid >> values). > > I don't follow here. If the value is outside the subtype, then that > is like a null-excluding access type. > You have to explicitly initialize it or you get a constraint_error. I > don't see how you end up with an invalid value. This is weird, so if we have type R is range 1 .. 10 with Default_Value => 1; subtype S is R range 2 .. 10; then X : S; will generate a constraint_Error, seems a bit awkward, but OK. **************************************************************** From: Bob Duff Sent: Monday, November 22, 2010 7:43 PM > Yes, of course. Even the type can have an invalid value: > > type Small_Int is range 0 .. 99 with Default_Value => -1; ...which might even be useful (can't declare objects), although I suppose: type T(<>) is private; is still preferable. > We answer that with the standard rules for inheritance of aspects. > However, we need to decide if this is representational or operational > to answer that, and then if the latter we still need to define it. So > I think this is a valid question, but the answer should clearly be > yes. (Why not??) I agree (derived types should inherit). **************************************************************** From: Robert Dewar Sent: Monday, November 22, 2010 8:07 PM One other question, do we really want to delay these expressions. In general it seems peculiar to delay static expression evaluation, e.g. Standard_Default : constant := 0; .... type R is range 0 .. 10 with Default_Value => Standard_Default; .. Standard_Default_Value constant := 1; RR : R; Do we really want to go to the trouble of insisting that the default value be 1 in this case, seems odd, and for sure makes the handling of the check for consistent visibility more tricky, since you don't know without fiddling at the freeze point what the resolving type will be. Well just raising the question, it's manageable either way with some fiddling! **************************************************************** From: Randy Brukardt Sent: Monday, November 22, 2010 8:29 PM > One other question, do we really want to delay these expressions. I think we have to, as otherwise the default value expression would have to freeze the type instantly. That doesn't seem desirable. > In general it seems peculiar to delay static expression evaluation, > e.g. > > Standard_Default : constant := 0; > > .... > > type R is range 0 .. 10 with > Default_Value => Standard_Default; > > .. > > Standard_Default_Value constant := 1; > > RR : R; > > Do we really want to go to the trouble of insisting that the default > value be 1 in this case, seems odd, and for sure makes the handling of > the check for consistent visibility more tricky, since you don't know > without fiddling at the freeze point what the resolving type will be. This is true, but immediate resolution/evaluation also means that you can't have a typed constant as the default value: type RLB is range 0 .. 10 with Default_Value => Unknown; Unknown : constant RLB := 0; This latter usage seems like the way I would write this, and I was rather expecting that it would work. **************************************************************** From: Robert Dewar Sent: Monday, November 22, 2010 8:49 PM >> One other question, do we really want to delay these expressions. > > I think we have to, as otherwise the default value expression would > have to freeze the type instantly. That doesn't seem desirable. You are right! > This is true, but immediate resolution/evaluation also means that you > can't have a typed constant as the default value: > > type RLB is range 0 .. 10 with Default_Value => Unknown; > Unknown : constant RLB := 0; > > This latter usage seems like the way I would write this, and I was > rather expecting that it would work. Agreed, it should work! **************************************************************** From: Bob Duff Sent: Monday, November 22, 2010 7:49 PM > This is weird, so if we have > > type R is range 1 .. 10 with > Default_Value => 1; > > subtype S is R range 2 .. 10; > > then > > X : S; > > will generate a constraint_Error, seems a bit awkward, but OK. Yes, weird/awkward, but OK. The "not null" thing is broken, IMHO, because the null-default is forced upon you. But here, you asked for "2..10", and you also asked for default of "1", so it makes perfect sense to ding you with C_E on "X : S;". This case is not broken, unlike the not-null access type case. **************************************************************** From: Robert Dewar Sent: Tuesday, November 23, 2010 4:18 PM Seems a pity you cannot use Initial_Value to control the creation of invalid values. **************************************************************** From: Bob Duff Sent: Tuesday, November 23, 2010 4:18 PM I don't understand what you mean by "control the creation...". If you say: package P is type T is private; ... private type T is range 200_000_000..400_000_000 with Default_Value => 0; -- default is invalid end P; then any client of P that says "X: T;" will get a Constraint_Error. If you leave off the "Default_Value", then no Constraint_Error. Programmer of P has full control. Is that not what you want? Where's the "seems a pity" here? **************************************************************** From: Robert Dewar Sent: Tuesday, November 23, 2010 6:42 PM I want to get a result similar to Normalize_Scalars, except selective, so variables are initialized with an invalid value, which will cause a constraint_Error when accessed (it's useless having the CE on creation for this purpose!) **************************************************************** From: Bob Duff Sent: Tuesday, November 30, 2010 1:50 PM This AI proposes attributes Default_Value and Default_Component_Value. Several of us at AdaCore think that the "_Value" part is just noise, so we would prefer Default and Component_Default. What do other ARG members think? P.S. If we must keep "_Value", I'd prefer Component_Default_Value over Default_Component_Value. **************************************************************** From: Randy Brukardt Sent: Tuesday, November 30, 2010 2:14 PM I tried a number of names when I created this AI; I thought "Default" by itself was too non-specific (there are a number of things that this could mean), thus I settled on "Default_Value". Note that any form of "Default" is really wrong, as the technical term in question is "implicit initial value". But "Implicit_Initial_Value" seems way too long. "Initial_Value" would be OK, but not clearly better than "Default_Value". ("Initial" by itself makes no sense.) As far as "Default_Component_Value" goes, that is what Jean-Pierre suggested during the meeting, no one suggested anything else, and honestly, "Component_Default_Value" sounds wrong and contrived. I suspect that I'd usually write "Default_Component_Value" and have to change it. **************************************************************** From: Gary Dismukes Sent: Tuesday, November 30, 2010 3:18 PM > Note that any form of "Default" is really wrong, as the technical term > in question is "implicit initial value". But "Implicit_Initial_Value" > seems way too long. "Initial_Value" would be OK, but not clearly > better than "Default_Value". ("Initial" by itself makes no sense.) I could live with Initial_Value. Actually I think I like it a bit better than Default_Value, and as you say, it fits better terminology-wise. > As far as "Default_Component_Value" goes, that is what Jean-Pierre > suggested during the meeting, no one suggested anything else, and > honestly, "Component_Default_Value" sounds wrong and contrived. I > suspect that I'd usually write "Default_Component_Value" and have to change it. Really? I parse Component_Default_Value as "component's default value" and Default_Component_Value as "default component's value". The former seems much better to me (it's what I mistakenly remembered as the chosen name in the AI). Obviously tastes vary. **************************************************************** From: Bob Duff Sent: Tuesday, November 30, 2010 4:37 PM > I could live with Initial_Value. Actually I think I like it a bit > better than Default_Value, and as you say, it fits better terminology-wise. I prefer Default_Value over Initial_Value, because it isn't really the initial value in all cases -- it's the *default* initial value; i.e. the one used when you don't specify an explicit one. Never mind the language-lawyerly terminology. Besides, this feature is intended to mirror the fact that record components can have defaults, and the syntax for those uses the term default_expression, so I think Default_Value (or just Default) fits in OK. Implicit_Initial_Value seems pretty awful to me. > > As far as "Default_Component_Value" goes, that is what Jean-Pierre > > suggested during the meeting,... Jean-Pierre speaks French, and they put their adjectives and nouns in a different order, so I'm not sure I trust his judgement here (despite his excellent English -- far better than my French!). >...no one suggested anything else, and honestly, > > "Component_Default_Value" sounds wrong and contrived. I suspect that > > I'd usually write "Default_Component_Value" and have to change it. > > Really? I parse Component_Default_Value as "component's default value" > and Default_Component_Value as "default component's value". The > former seems much better to me (it's what I mistakenly remembered as > the chosen name in the AI). Obviously tastes vary. In this case, my taste matches Gary's. It's the "default value" for the component, not the "default" for the "component value", whatever that might mean. I also agree with Tucker's reasoning, but he hasn't weighed in on Component_Default_Value (nor Component_Default). **************************************************************** From: Gary Dismukes Sent: Tuesday, November 30, 2010 4:59 PM > I prefer Default_Value over Initial_Value, because it isn't really the > initial value in all cases -- it's the *default* initial value; i.e. > the one used when you don't specify an explicit one. > Never mind the language-lawyerly terminology. > > Besides, this feature is intended to mirror the fact that record > components can have defaults, and the syntax for those uses the term > default_expression, so I think Default_Value (or just Default) fits in > OK. Good points. The Default_* names seem preferable. > Implicit_Initial_Value seems pretty awful to me. Agreed (and I don't think anyone's arguing for that). **************************************************************** From: Randy Brukardt Sent: Tuesday, November 30, 2010 5:26 PM ... > > I could live with Initial_Value. Actually I think I like it a bit > > better than Default_Value, and as you say, it fits better terminology-wise. > > I prefer Default_Value over Initial_Value, because it isn't really the > initial value in all cases -- it's the *default* initial value; i.e. > the one used when you don't specify an explicit one. > Never mind the language-lawyerly terminology. I'd argue that it is OK to think of it as the initial value in all cases, as there is no side-effects to the evaluation of it and any explicit value would overwrite it (allowing the compiler to eliminate the initial assignment). That is, there is no difference between thinking of it as an always present initial value and an implicit initial value used only when nothing else is specified. > Besides, this feature is intended to mirror the fact that record > components can have defaults, and the syntax for those uses the term > default_expression, so I think Default_Value (or just Default) fits in > OK. > > Implicit_Initial_Value seems pretty awful to me. I do agree with that; it's just too long. > > > As far as "Default_Component_Value" goes, that is what Jean-Pierre > > > suggested during the meeting,... > > Jean-Pierre speaks French, and they put their adjectives and nouns in > a different order, so I'm not sure I trust his judgement here (despite > his excellent English -- far better than my French!). > > >...no one suggested anything else, and honestly, > > > "Component_Default_Value" sounds wrong and contrived. I suspect > > > that I'd usually write "Default_Component_Value" and have to change it. > > > > Really? Yes. > I parse Component_Default_Value as "component's default value" > > and Default_Component_Value as "default component's value". The > > former seems much better to me (it's what I mistakenly remembered as > > the chosen name in the AI). Obviously tastes vary. But there is no possessive in these names, you're adding that for some mysterious reason to me. I parse "Default_Component_Value" as "default 'component value'" which rearranged gives "default value of a component". I can't parse "Component_Default_Value" at all; I would need to put the possessive explicitly into the identifier in order to do that -- but that's impossible as ' can't be used in an identifier (I always rearrange identifiers when that happens). Indeed, I'd be much more likely to use "Default_Value_of_Component" than either of the proposed names if this was my code. > In this case, my taste matches Gary's. It's the "default value" > for the component, not the "default" for the "component value", > whatever that might mean. > > I also agree with Tucker's reasoning, but he hasn't weighed in on > Component_Default_Value (nor Component_Default). Tucker? He hasn't weighed in at all, at least on the ARG list where I can see it. Did you mean someone else, or is this discussion going on somewhere else?? **************************************************************** From: Erhard Ploedereder Sent: Tuesday, November 30, 2010 5:29 PM I agree on "Default" over "Initial" (for the same reason as cited below.). On the component values, ... etymologically interesting discussion :-) Germans, being world champions in glueing words together to form new terms, would never think of a syntax to do so. (Of course the correct syntax is * +.) For "Initial", this would have clearly argued for Initial_Component_Value. For "Default", it's a wash. **************************************************************** From: Robert Dewar Sent: Tuesday, November 30, 2010 5:35 PM Why don't we just leave it the way it is? There really seems no consensus for a change :-) **************************************************************** From: Bob Duff Sent: Tuesday, November 30, 2010 7:09 PM > I'd argue that it is OK to think of it as the initial value in all > cases, as there is no side-effects to the evaluation of it and any > explicit value would overwrite it (allowing the compiler to eliminate > the initial assignment). That is, there is no difference between > thinking of it as an always present initial value and an implicit > initial value used only when nothing else is specified. True. But I don't like that way of thinking for the same reason I wouldn't write "X: T := 0; X := 1; ...", where the "0" is not used. > > I also agree with Tucker's reasoning, but he hasn't weighed in on > > Component_Default_Value (nor Component_Default). > > Tucker? He hasn't weighed in at all, at least on the ARG list where I > can see it. Did you mean someone else, or is this discussion going on > somewhere else?? Sorry. There was a private email discussion. I then started this ARG discussion, and then admonished everybody to reply to that, but they all replied to the private discussion instead. Sigh. Anyway, Tuck's point was that Default_Component doesn't make sense. He can repeat it here, if he likes, and possibly comment on whether he likes Component_Default better. **************************************************************** From: Robert Dewar Sent: Tuesday, November 30, 2010 7:17 PM >> I'd argue that it is OK to think of it as the initial value in all >> cases, as there is no side-effects to the evaluation of it and any >> explicit value would overwrite it (allowing the compiler to eliminate >> the initial assignment). That is, there is no difference between >> thinking of it as an always present initial value and an implicit >> initial value used only when nothing else is specified. Also you don't get a constraint_error if this initial value is out of range if it is superceded by an explicit value, so that's another reason for not liking this viewpoint (and name!) **************************************************************** From: Tucker Taft Sent: Tuesday, November 30, 2010 10:04 PM >> I also agree with Tucker's reasoning, but he hasn't weighed in on >> Component_Default_Value (nor Component_Default). > > Tucker? He hasn't weighed in at all, at least on the ARG list where I > can see it. Did you mean someone else, or is this discussion going on > somewhere else?? There were some messages passed around among a small group (mostly AdaCore), before Bob posted the note to ARG. I indicated I didn't like Default_Component. Component_Default, Component_Default_Value, and Default_Component_Value are all fine with me. Default_Value is preferable to Default as far as I am concerned, though only marginally. Overall, sticking with "Default_Value" and "Default_Component_Value" seems easiest at this point, because, as Robert pointed out, there is no consensus about what to change to. **************************************************************** From: Brad Moore Sent: Wednesday, December 1, 2010 1:00 AM For what its worth, my view is similar to Tuckers, but if I had to choose, I like Default_Value and Default_Component_Value the best anyway. **************************************************************** From: Robert Dewar Sent: Monday, December 6, 2010 10:11 AM I am having HUGE problems with implementing this aspect, and finally had to give up in a certainly sense. The trouble is that the aspect expression is resolved with the type to which the aspect is applied. Normally for an aspect like Size, specifying an aspect: type R is ... with Size => S; corresponds to having an attribute definition for R'Size use S; just before R is frozen. Now for this to be OK, we can't have S be an expression that freezes R, for instance, we must reject For R'Size use R'Component_Size; Now in the case of Default_Value, the corresponding attribute definition for R'Default_Value use expr; is problematic, since resolving expr with R will in general freeze R. The only way I found to deal with this was to resolve expr with Any_Integer, and then convert to type R when it is actually used (I could also check the bounds after R is frozen). **************************************************************** From: Tucker Taft Sent: Monday, December 6, 2010 10:27 AM Interesting problem. I suppose there is no great harm in freezing the type, since you don't really need the default value until you create an uninitialized object of the type, and that will clearly come after processing the "Default_Value" aspect specification. From an ordering point of view, it would tend to force you to handle these sorts of "freezing" aspect specifications after all the ones that must clearly precede freezing (such as a Size specification). If you think about it, the default value for the fields of a record are generally determinable after the record type is laid out, so this one seems somewhat similar. **************************************************************** From: Robert Dewar Sent: Monday, December 6, 2010 10:43 AM That would require huge amounts of additional mechanism. Probably we just won't implement it in this form, since it is too disruptive. In fact the approach I have, which is to resolve with any integer, and then check the bounds later, works fine in practice and I don't think we will worry about marginal cases where the difference is noticable. **************************************************************** From: Tucker Taft Sent: Monday, December 6, 2010 11:38 AM It might be noticeable for an enumeration or real type ;-). **************************************************************** From: Randy Brukardt Sent: Monday, December 6, 2010 12:36 PM I was thinking the same thing. The motivating example for this aspect was type Status_Kind is (Unknown, Open, Transmitting, ...) with Default_Value => Unknown; which would not resolve by the approach given here. But I do think that these can be implemented reasonably easily. The key is to note that as these have to be static expressions, they can't involve the creation of any default-initialized objects (no user-defined function calls). Thus, I would suggest that the best approach would be to handle Default_Value aspects immediately *after* freezing of the type (but before anything else that depends on freezing. That is, the only thing done before freezing is to ensure that the aspect was given before freezing (only necessary if you have a matching pragma versions). The rest of the processing for Default_Value happens after the freezing of the type. If there is anything that would be a problem, the checking for a static expression will catch it. I wouldn't expect this ordering to require "huge additional mechanisms", because the resolution and legality checking code can remain untouched (as the type is already frozen, and we don't care about any freezing detection for this type). Only the freezing code itself would require some additional ordering. Hope this helps... P.S. I was originally concerned about the freezing of these expressions, but the lack of complaints from Steve Baird convinced me that there was no problem. Perhaps I'm getting too dependent on Steve. :-) **************************************************************** From: Robert Dewar Sent: Monday, December 6, 2010 3:35 PM > It might be noticeable for an enumeration or real type ;-). Indeed we have to do something special there. This is a huge pain. For now I am just abandoning Default_Value entirely. Maybe next year :-( **************************************************************** From: Robert Dewar Sent: Monday, December 6, 2010 3:39 PM > I was thinking the same thing. The motivating example for this aspect > was > > type Status_Kind is (Unknown, Open, Transmitting, ...) with > Default_Value => Unknown; > > which would not resolve by the approach given here. It's very fundamental to the GNAT approach for aspects that they be translatable to a pragma or attribute definition clause which can be inserted at the appropriate point. This works fine for all aspects except Current_Value, and putting in a whole different mechanism for this one aspect is infeasible. In fact I believe that Bob was suggesting that the attribute Default_Value be added to the standard. This suggestion is probably a bad idea, since I certainly don't see how you would use the attribute definition clause. > I wouldn't expect this ordering to require "huge additional > mechanisms", because the resolution and legality checking code can > remain untouched (as the type is already frozen, and we don't care > about any freezing detection for this type). Only the freezing code > itself would require some additional ordering. Well it does, so for now I am just abandoning trying to implement this aspect, it won't be in GNAT in 2011, it might be there in 2012, but I doubt it, it's just too much trouble to implemenyt. > Hope this helps... Not enough :-( **************************************************************** From: Jean-Pierre Rosen Sent: Monday, December 6, 2010 3:59 PM > In fact I believe that Bob was suggesting that the attribute > Default_Value be added to the standard. This suggestion is probably a > bad idea, since I certainly don't see how you would use the attribute > definition clause. But what about a pragma? After all, such a pragma gives a special value to something that (without the pragma) can be any value. So a pragma is not inappropriate, and it could appear right after freezing. **************************************************************** From: Ed Schonberg Sent: Tuesday, December 7, 2010 7:40 AM > Indeed we have to do something special there. This is a huge pain. For > now I am just abandoning Default_Value entirely. > Maybe next year :-( For numeric types the default value cannot involve any entity of the type (we can agree to forbid attributes) and given that it must be a static value it can be resolved by itself, with its own type (determinable in the first pass of analysis, or just universal). So I don't see the problem of resolving the expression at the point of the aspect itself. Any subsequent use of the default involves an unchecked conversion to the type, and those can only occur after the type is frozen. For enumeration types we need some special mechanism to make the literals visible, because it's attractive to use a literal of the type as the default. Doesn't seem too hard either. **************************************************************** From: Bob Duff Sent: Tuesday, December 7, 2010 9:17 AM > > In fact I believe that Bob was suggesting that the attribute > > Default_Value be added to the standard. This suggestion is probably > > a bad idea, since I certainly don't see how you would use the > > attribute definition clause. This was in a phone conversation between me and Robert, where Robert was talking about turning a Default_Value clause into a Default_Value pragma. I suggested using an attribute instead of a pragma, not so you can use an attribute definition clause, but so you can query it. You can't query a pragma. My thinking was that this: T_Default : constant T := ...; type T is ... with Default_Value => T_Default; ... T_Default ... -- refer to it has to be illegal (no matter what order you write it), because of visibility and freezing rules. And that's unfortunate, because you might want to refer to that default value without repeating the expression. If it's an attribute, you could say: type T is ... with Default_Value => ...; ... T'Default_Value ... -- refer to it > But what about a pragma? After all, such a pragma gives a special > value to something that (without the pragma) can be any value. So a > pragma is not inappropriate, and it could appear right after freezing. You mean a pragma that is also an aspect, or just a pragma totally unrelated to the aspect syntax? It's a little tricky either way, because I assume you'd either want to forbid creating objects before the pragma, or make them have a default based on a later pragma. But since it's static, there's got to be some way to implement this without standing on our heads! On the other hand, I'm not going to cry if this feature doesn't get into Ada 2012. **************************************************************** From: Bob Duff Sent: Tuesday, December 7, 2010 9:21 AM > For enumeration types we need some special mechanism to make the > literals visible, because it's attractive to use a literal of the type > as the default. Doesn't seem too hard either. So are you saying that it has to be a literal, so this: type Color is (Red, Orange) with Default_Value => Color'Succ(Color'First); is illegal? Reminds me of annoying restrictions in Pascal. But I suppose if it makes the thing implementable, such a restriction is OK. Maybe we should say "shall be a literal", rather than letting people deduce that fact from freezing and other rules. **************************************************************** From: Robert Dewar Sent: Tuesday, December 7, 2010 9:36 AM > But what about a pragma? After all, such a pragma gives a special > value to something that (without the pragma) can be any value. So a > pragma is not inappropriate, and it could appear right after freezing. I am actually researching the issue of simply allowing the rep clause to appear AFTER the freezing point in this case, which is not so unreasonable here. Not much differene between a representation pragma and a attribute clause, the issue in both cases is whether they have to come before the freeze point. **************************************************************** From: Robert Dewar Sent: Tuesday, December 7, 2010 9:39 AM ... > is illegal? Reminds me of annoying restrictions in Pascal. > But I suppose if it makes the thing implementable, such a restriction > is OK. Maybe we should say "shall be a literal", rather than letting > people deduce that fact from freezing and other rules. How about my idea of simply allowing this after the freeze point. We can make object declarations preceding the attribute definition clause (which can't happen of course for the aspect syntax) illegal, seems MUCH simpler than trying to reach back and retrofit a default declared later. **************************************************************** From: Robert Dewar Sent: Tuesday, December 7, 2010 9:40 AM Actually here is another idea for J'Default_Value use bla; Cannot appear after J is frozen Always freezes J Analyzes bla after freezing J So you can even have for J'Default_Value use J'Size; odd, but why not for J'Default_Value use J'Default_Value; has to be diagnosed, but this is truly marginal anyway. **************************************************************** From: Jean-Pierre Rosen Sent: Tuesday, December 7, 2010 9:43 AM > I am actually researching the issue of simply allowing the rep clause > to appear AFTER the freezing point in this case, which is not so > unreasonable here. Not much differene between a representation pragma > and a attribute clause, the issue in both cases is whether they have > to come before the freeze point. The whole issue is that this is an aspect of the type which is not a /representation/ aspect. That's why it has nothing to do with freezing. My simple model (but I don't know the internals of the compiler) is that if you specify pragma Default_Value (), everything within the scope of the pragma would use the default. Too bad for variables declared before the pragma. If the aspect is given with an aspect clause, then it is as if the pragma appeared right after the freezing point. **************************************************************** From: Robert Dewar Sent: Tuesday, December 7, 2010 9:48 AM > My simple model (but I don't know the internals of the compiler) is > that if you specify pragma Default_Value (), everything within > the scope of the pragma would use the default. Too bad for variables > declared before the pragma. I do not like being able to specify this pragma anywhere, I think the first argument of the pragma MUST be a local name. > If the aspect is given with an aspect clause, then it is as if the > pragma appeared right after the freezing point. But it is equally easy to do this with an attribute rather than a pragma. **************************************************************** From: Bob Duff Sent: Tuesday, December 7, 2010 10:25 AM > How about my idea of simply allowing this after the freeze point. OK. >... We can make object declarations preceding the attribute definition >clause (which can't happen of course for the aspect > syntax) illegal, seems MUCH simpler than trying to reach back and >retrofit a default declared later. The rule is something like, "Before a Default_Val clause for T, it is illegal to declare an object that has a part of type T". To cover records containing T, and so on. Same thing for "new ...". But in this model, when you have aspect syntax, where do you stick in the implicit attribute_defn_clause? > Actually here is another idea > > for J'Default_Value use bla; > > Cannot appear after J is frozen > Always freezes J > Analyzes bla after freezing J OK. So it's sort of like: for J'Default_Value use bla; ^ Freezing point is right there? And I have the same question as above: ... in this model...where do you stick...? I guess the answer is just before the first freezing point. But then you're inserting a new first freezing point -- a little tricky, but doable, I suppose. > So you can even have > > for J'Default_Value use J'Size; > > odd, but why not > > for J'Default_Value use J'Default_Value; > > has to be diagnosed, but this is truly marginal anyway. And "... use J'Default_Value + 1", and so forth. **************************************************************** From: Tucker Taft Sent: Tuesday, December 7, 2010 10:43 AM I presume this whole discussion is relevant only to GNAT's desire to have an equivalent pragma or attribute definition. For those who implement aspect specifications directly, everything happens at the freezing point or infinitesimally thereafter. **************************************************************** From: Bob Duff Sent: Tuesday, December 7, 2010 10:53 AM > I presume this whole discussion is relevant only to GNAT's desire to > have an equivalent pragma or attribute definition. For those who > implement aspect specifications directly, everything happens at the > freezing point or infinitesimally thereafter. I suppose so. But for aspects that are also pragmas or attributes, you don't want to implement them twice -- you want to implement one form in terms of the other. And for an existing implementation, that means aspects in terms of pragmas/attributes. (Anybody implementing a new Ada compiler from scratch, these days?! ;-)) And for new aspects that do not correspond to language-defined pragmas/attributes, it makes sense to invent pragmas/attributes just for the implementation, for uniformity. So I don't really think this is GNAT-specific. But I guess something special/non-uniform needs to be done for Default_Value (or we need to get rid of it, or define it in some other way not involving aspects). **************************************************************** From: Tucker Taft Sent: Tuesday, December 7, 2010 11:23 AM > ... But I guess something special/non-uniform needs to be done for > Default_Value (or we need to get rid of it, or define it in some other > way not involving aspects). Why "not involving aspects"? What does that accomplish? **************************************************************** From: Bob Duff Sent: Tuesday, December 7, 2010 12:00 PM I was thinking that then it wouldn't involve all the "normal" rules about freezing re: aspects. But maybe that's just nonsense -- I don't know. **************************************************************** From: Randy Brukardt Sent: Tuesday, December 7, 2010 1:15 PM > Actually here is another idea > > for J'Default_Value use bla; > > Cannot appear after J is frozen > Always freezes J > Analyzes bla after freezing J ... This is definitely a good idea, because it is what I tried to suggest yesterday. :-) **************************************************************** From: Randy Brukardt Sent: Tuesday, December 7, 2010 1:30 PM > > I presume this whole discussion is relevant only to GNAT's desire to > > have an equivalent pragma or attribute definition. For those who > > implement aspect specifications directly, everything happens at the > > freezing point or infinitesimally thereafter. > > I suppose so. But for aspects that are also pragmas or attributes, > you don't want to implement them twice -- you want to implement one > form in terms of the other. > And for an existing implementation, that means aspects in terms of > pragmas/attributes. > (Anybody implementing a new Ada compiler from scratch, these days?! > ;-)) I don't buy this. I agree that you don't want to implement them twice, but it's the internal form drives that, not some particular syntax. Indeed, for Janus/Ada (which is a classic Dragon Book design), it's impossible to implement anything with different syntax in the same way, since it is the syntax that drives the translation. But it is possible to convert both syntaxes into the same internal form. (Each scope has a list of pending aspect clauses for unfrozen types.) Although in this case even that isn't possible, as in the attribute/pragma case you can resolve everything immediately (and of course the internal form reflects that), while that is not possible for an aspect clause. So even the internal forms need to be somewhat different. Of course those forms can share the actual processing code -- such as handling 'Size, but this is so far separated from the syntactic forms that they are completely irrelevant. Moral: never assume *anything* about someone else's implementation. You're probably wrong. :-) > And for new aspects that do not correspond to language-defined > pragmas/attributes, it makes sense to invent pragmas/attributes just > for the implementation, for uniformity. Do you insist that your car has a carburetor "for uniformity"? Or a buggy whip holder? Pragmas and attributes are obsolete IMHO; no one ought to be using them in new programs any more than they ought to be using address clauses. I think Robert's argument about using them in Ada 95/2005 code makes more sense; it's not about "uniformity", it's about backwards compatibility. > So I don't really think this is GNAT-specific. It is. There is no good reason for a 'Default_Value attribute. (And I don't buy your argument about wanting to read it. For numeric types, a named number works fine, you don't need a typed constant. For enumerations [which inherently are named], you are much better initializing with the named literal rather than some attribute with an unknown value.) A pragma makes more sense, IMHO, but only if you think that pragmas ought to have these sort of effects. (I hate pragmas.) > But I guess something special/non-uniform needs to be done for > Default_Value (or we need to get rid of it, or define it in some other > way not involving aspects). All aspects require at least some special processing, so I can't get too worried about this one being a bit more different than the others. **************************************************************** From: Robert Dewar Sent: Tuesday, December 7, 2010 2:55 PM > All aspects require at least some special processing, so I can't get > too worried about this one being a bit more different than the others. Actually in GNAT, this is the ONLY aspect that needs special processing, most aspects just transform into pragmas and attribute definition clauses (most of which already exist in the language, most of the rest already existed in GNAT, e.g. precondition, and we just had to invent a few extra ones (e.g. aspect), but Default_Value is definitely different from all the others, since its placement and semantics are definitely delicate wrt freezing. **************************************************************** From: Robert Dewar Sent: Tuesday, December 7, 2010 2:59 PM > Pragmas and attributes are obsolete IMHO; no one ought to be using > them in new programs any more than they ought to be using address clauses. Nonsense, it is often appropriate to have pragmas and attributes in the private part, since they are none of the clients business, e.g. pragma Inline, and aspects don't handle this case. Fine if you prefer to use aspects, but please don't impose this usage view on others, no more than you should impose your peculiar anti-use views on others. I would strongly oppose moving the pragmas and attributes to annex J, not that it has any effect, but becuase it smacks of trying to impose your style on others > I think Robert's argument about using them in Ada 95/2005 code makes > more sense; it's not about "uniformity", it's about backwards compatibility. > >> So I don't really think this is GNAT-specific. > > It is. There is no good reason for a 'Default_Value attribute. (And I > don't buy your argument about wanting to read it. For numeric types, a > named number works fine, you don't need a typed constant. For > enumerations [which inherently are named], you are much better > initializing with the named literal rather than some attribute with an > unknown value.) A pragma makes more sense, IMHO, but only if you think > that pragmas ought to have these sort of effects. (I hate pragmas.) I think the 'Default_Value attribute is indeed useful, in a case where you want to initialize with a safe value, but do not want to specify a local value different from the standard default. **************************************************************** From: Jean-Pierre Rosen Sent: Tuesday, December 7, 2010 3:24 PM > (Anybody implementing a new Ada compiler from scratch, these days?! > ;-)) There might be. See the Tendra project (http://www.ten15.org/), but the site seems to be down currently. TBH, I see this project as having as many chances of succeeding as the many Ada-only OSes everybody is dreaming of... **************************************************************** From: Arnaud Charlet Sent: Wednesday, December 8, 2010 2:18 AM > There might be. See the Tendra project (http://www.ten15.org/), but > the site seems to be down currently. This seems to be a C compiler though: << TenDRA is a C compiler, with C++ STL support forthcoming. >> **************************************************************** From: Bob Duff Sent: Wednesday, December 8, 2010 12:52 PM If you look over on the right-hand side of the page, there's something about Ada, which you can click on. **************************************************************** From: Jean-Pierre Rosen Sent: Thursday, December 9, 2010 1:24 AM "Ada compiler" is in the box to the right. **************************************************************** From: Robert Dewar Sent: Thursday, December 9, 2010 2:57 AM I am making some progress by treating Current_Value differently and NOT having a pragma or attribute definition clause. It is interesting that the work on Default_Value has been approximately similar to the work on all other aspects combined :-( **************************************************************** From: Robert Dewar Sent: Sunday, December 12, 2010 6:41 AM First, I have finally managed to implement this by abandoning having a corresponding pragma or attribute, a little inconsistent in the GNAT environment, but no big deal. But now, some musings First of all, a methodological issue, I see two reasons for using Current_Value: a) avoid non-deterministic behavior from using uninitialized variables, a variant on Normalize_Scalars (which doesn't work so well in practice, because of the requirement for partition wide consistency). b) provide initial values that are used by the program. I am not quite clear on which is the intended use. I am a little concerned about a), why? Because reference to uninitialized variables is a major source of bugs, and usage like a) can actually hide such problems and work against finding them. Why? Because it disables the use of pragma Initialize_Scalars in GNAT, a super-valuable tool in finding UI references. In GNAT, IS initializes all scalars and you can control at bind time or even execution time what the initial value is. By changing the initial value, and seeing if the behavior of the program changes, you can find UI references. Not really a language issue, as the subject says, more like methodological musings. Second point, Default_Component_Value has to be used with care. If you play the trick of giant virtual arrays which are not committed till used, you can really mess things up using this aspect. Again a methodological issue. I think there are special ways of avoiding this effecct in some OS's with zero initial values, to be investigated. **************************************************************** From: Randy Brukardt Sent: Monday, December 13, 2010 10:49 PM ... > I am not quite clear on which is the intended use. I can't speak for everyone, but my thinking was that this feature would be useful in two cases: (1) Where there is a natural value to use as the initial value of all objects of the type (for instance, when an enumeration includes a literal like "unknown"); and (2) When the initial value is set out-of-range for a type, to ensure that all objects are initialized. (1) is pretty much your case (b), although of course it also has the effect of eliminating non-deterministic behavior. (2) is mostly about your case (a); but it avoids the non-deterministic behavior by replacing it by an exception. One could also use it to initialize values to an in-range value (what I think you suggested as case (a)), but that seems like a good way to cover up bugs. (I recall one Robert Dewar complaining about such features at the outset of the discussion that led to this proposal.) So I don't consider that an important usage. > I am a little concerned about a), why? > > Because reference to uninitialized variables is a major source of > bugs, and usage like a) can actually hide such problems and work > against finding them. That's true assuming that the initial value is valid for the first subtype; if it is *not* valid for the first subtype, then it will always raise an exception and surely that won't allow any bugs to be hidden. (But it also will cause false positives in some cases.) > Why? Because it disables the use of pragma Initialize_Scalars in GNAT, > a super-valuable tool in finding UI references. > > In GNAT, IS initializes all scalars and you can control at bind time > or even execution time what the initial value is. > By changing the initial value, and seeing if the behavior of the > program changes, you can find UI references. > > Not really a language issue, as the subject says, more like > methodological musings. Right. I can imagine a style guide having fairly significant guidelines about the use of these aspects. > Second point, Default_Component_Value has to be used with care. If you > play the trick of giant virtual arrays which are not committed till > used, you can really mess things up using this aspect. Again a > methodological issue. I think there are special ways of avoiding this > effecct in some OS's with zero initial values, to be investigated. Right again, but of course this isn't new. You can have the same problem (in any version of Ada) with an access component or a component of a record type where one or more components have a default initialization. Indeed, that happened to me with my Freecell solver years ago -- initializing 2 GB of memory on a 512K machine was not the best use of execution time! I had to get rid of the implicit initializations. These aspects (both of them, in fact) provide new ways to cause this existing problem. Can't get very excited about that. **************************************************************** From: Bob Duff Sent: Tuesday, December 14, 2010 8:45 AM > I can't speak for everyone, but my thinking was that this feature > would be useful in two cases: > (1) Where there is a natural value to use as the initial value of all > objects of the type (for instance, when an enumeration includes a > literal like "unknown"); and > (2) When the initial value is set out-of-range for a type, to ensure > that all objects are initialized. I agree with Randy about the intended purpose of the feature. When you put it that way, it seems clear that it isn't the purpose to hide bugs! ;-) Or to put it another way, if you might wrap the scalar in a record, just so you can default-initialize it, the purpose of the feature is to avoid the wrapping. This is independent of the question of whether it is wise to have a default for that type. And that wrapping can be extremely painful in my experience -- the code is filled with "X.Thing" (bad), and "(Thing => X)" (worse) obscuring the code that does useful work. ****************************************************************