!standard 4.9(9) 17-07-19 AI12-0201-1/02 !standard 4.9(19) !standard 4.9(20) !standard 4.9(24) !class Amendment 16-08-18 !status Amendment 1-2012 17-07-19 !status ARG Approved 9-0-0 17-06-18 !status work item 16-08-18 !status received 16-07-29 !priority Low !difficulty Easy !subject Missing operations of static string types !summary Relational operators and type conversions of static string types are now static. !problem The general model for static predicates is that if you replace the current instance with a static expression, then the whole predicate expression would end up static (see discussion in AI05-0153-3: " ... Every predicate-static expression necessarily has the property that if you plug in a static expression in place of every occurrence of the current instance, you get a static expression. ... "). However, for string subtypes, this model breaks down. As currently defined, a static predicate for a string can use relational operators on strings (RM 3.2.4(19/3)), whereas a static expression on strings cannot, because the corresponding operators are not "static functions" (RM 4.9(19)). Now that we have static membership tests for strings (e.g. S in "abc" -- RM 4.9(11/4)) it seems odd to not permit static equality tests for strings (e.g. S = "abc"). We should be extending static functions to include relational operators on strings. !proposal (See Summary.) !wording Add after AARM 4.9(1.d): Reason: We support static string expressions so that, for example, the aspect_definition for a Link_Name aspect can contain a concatenation. We don't support static aggregates (even for string types) or non-string static nonscalar types; we're trying to keep it cheap and simple (from the implementer's viewpoint). [Editor's note: Most of this was moved from 4.9(24.b), which was mainly about the (now deleted) length limit. The remainder is more general text that should be at the start. Note that this text admits that static strings are really a hack; this AI makes them a little bit less hacky, but there seems to be little reason that (say) an array of scalar couldn't also be static.] Modify 4.9(9): * a type_conversion whose subtype_mark denotes a static [scalar]{@Redundant[(scalar or string)]} subtype, and whose operand is a static expression; Add after 4.9(19): * a predefined relational operator whose parameters are of a string type that is not a descendant of a formal array type; Modify 4.9(20): * a predefined concatenation operator whose result type is a string type {that is not a descendant of a formal array type}; [Editor's note: A formal array type can be a string type (it can be one-dimensional with a character type as a component), and since we don't allow predefined operators of formal scalar types, it seems that we need the matching case for formal string types. Why we'd allow that for formal string types and not for formal scalar types is beyond me, so I consider it an omission and fixed the concatenation rule.] Modify 4.9(24): A *static constant* is a constant view declared by a full constant declaration or an object_renaming_declaration with a static nominal subtype, having a value defined by a static scalar expression or by a static string expression[ whose value has a length not exceeding the maximum length of a string_literal in the implementation]. Delete AARM 4.9(24.b/3 and 24.c). !discussion There are three items where static strings have limited capabilities compared to static scalar types: operators, type conversions, and literals (aggregates). It's not clear why any of these were excluded originally -- perhaps the entire static string capability was more a hack than a designed feature. (This interpretation is backed up by 4.(24.b), which says that the feature was intended to be "cheap and simple".) The problem covered the uses for operators. Type conversions can be useful if a bounds change or a representation change is needed. A string literal is supposed to be equivalent to a positional array aggregate, but the aggregate is not static while the literal is. We make changes to cover the first two cases. The wording needed to allow aggregates seems extensive and complex, so we don't bother. (Static strings still is a hack. ;-) Note that for a type conversion, it might be necessary to change the representation of the components (if the compiler uses the final representation for the components in the internal static representation). This operation is similar to the one needed to process string literals, so it shouldn't provide an implementation hardship. We also remove the length limit for static strings. This limit bizarrely only applied to constant declarations; a string of concatenated static strings could exceed this limit without error. Thus, compilers have to support storing "giant strings" (as AARM 4.9(24.b/3) justifies the limit), at least momentarily, and it's hard to imagine that this limit saves much if any implementation effort. It mainly provides a "road hazard" making code illegal mysteriously, so we eliminate it. !corrigendum 4.9(9) @drepl @xbullet whose @fa denotes a static scalar subtype, and whose operand is a static expression;> @dby @xbullet whose @fa denotes a static (scalar or string) subtype, and whose operand is a static expression;> !corrigendum 4.9(19) @dinsa @xbullet @dinst @xbullet !corrigendum 4.9(20) @drepl @xbullet @dby @xbullet !corrigendum 4.9(24) @drepl A @i is a constant view declared by a full constant declaration or an @fa with a static nominal subtype, having a value defined by a static scalar expression or by a static string expression whose value has a length not exceeding the maximum length of a @fa in the implementation. @dby A @i is a constant view declared by a full constant declaration or an @fa with a static nominal subtype, having a value defined by a static scalar expression or by a static string expression. !ASIS No ASIS effect. !ACATS test An ACATS C-Test is needed to check that the new capabilities are supported. !appendix From: Tucker Taft Sent: Friday, July 29, 2016 8:07 AM The general model for static predicates is that if you replace the current instance with a static expression, then the whole predicate expression would end up static (see discussion in AI05-0153-3: " ... Every predicate-static expression necessarily has the property that if you plug in a static expression in place of every occurrence of the current instance, you get a static expression. ... "). However, for string subtypes, this model breaks down. As currently defined, a static predicate for a string can use relational operators on strings (RM 3.2.4(19/3)), whereas a static expression on strings cannot, because the corresponding operators are not "static functions" (RM 4.9(19)). We could leave this inconsistency as is, or we could fix this two different ways: 1) Disallow string relational operators in static predicates 2) Allow string relational operators in static expressions (presumably by enlarging the definition of "static function" a bit) Now that we have static membership tests for strings (e.g. S in "abc" -- RM 4.9(11/4)) it seems odd to not permit static equality tests for strings (e.g. S = "abc"). So I would recommend extending static functions to include relational operators on strings. **************************************************************** From: Tullio Vardanega Sent: Monday, August 1, 2016 5:25 AM I second. **************************************************************** From: Randy Brukardt Sent: Monday, August 1, 2016 4:12 PM For what it's worth, that was one of the reasons that my attempted extension of staticness to user-defined types didn't work out very well. The intent was to replace "static string subtype" with "potentially static subtype", but the fact that various operations that have no reason not to be static weren't included (like relational operations) turned the idea into a huge bunch of changes. In addition to relational operators, type conversions and aggregates aren't allowed as static for strings. For type conversions, 4.9(9) explicitly only mentions static scalar subtypes. Why the difference? There doesn't seem to be any difficulty in supporting that. As for aggregates, I presume the reason that they weren't allowed was simply a lack of need; but it's a wart as usually string literals are just a short-hand for a positional array aggregate. I'd suggest at least including type conversions along with relational operators. Aggregates are probably more work than they are worth (in the absence of the generalization I was previously proposing). You can find my original write-up of my proposed extension to staticness in AI12-0175-1/01 (make sure you look at version /01; the final AI is very different). The link is: http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0175-1.txt?rev=1.2 Not sure that there is anything else useful there, but I *did* already consider these issues, it might help to avoid reinventing the wheel. **************************************************************** From: Randy Brukardt Sent: Thursday, August 18, 2016 11:25 PM > Now that we have static membership tests for strings (e.g. S in "abc" > -- RM 4.9(11/4)) it seems odd to not permit static equality tests for > strings (e.g. S = "abc"). Attached is the AI I wrote for this thread [this is version /01 of the AI - Editor]; I'm posting it just in case Tucker gets ambitious -- I'd hate for him to repeat my work. **************************************************************** From: Jeff Cousins Sent: Tuesday, August 23, 2016 9:30 AM Looks an ok write-up to me, thanks Randy, **************************************************************** From: Jeff Cousins Sent: Monday, September 5, 2016 8:15 AM I'm probably going to regret asking this, but... Whilst we're on the subject of static-ness, what was the background behind only scalars and strings being static, and no other composites? It has long confused users that code such as: package Pure_Test1 is pragma Pure; type Node_Array_Type is array (0..63) of Boolean; type Node_Array_Record_Type is record Node_Array : Node_Array_Type; end record; Null_Node_Array_Record : constant Node_Array_Record_Type := (Node_Array => (others => False)); end Pure_Test1; is valid, but not: package Pure_Test2 is pragma Pure; type Node_Array_Type is array (0..63) of Boolean; Null_Node_Array : constant Node_Array_Type := (others => False); type Node_Array_Record_Type is record Node_Array : Node_Array_Type; end record; Null_Node_Array_Record : constant Node_Array_Record_Type := (Node_Array => Null_Node_Array); end Pure_Test2; even though it is generally preferred to use named objects and types rather than anonymous ones. **************************************************************** From: Bob Duff Sent: Monday, September 5, 2016 10:42 AM > Whilst we're on the subject of static-ness, what was the background > behind only scalars and strings being static, and no other composites? Ada 83 was scalars only. We added static strings in Ada 95 to support pragmas that need them (link names and so forth). And there's a 200 character limit, so it's not a fully general feature. I think concerns were ease of implementation, and ease of efficient implementation (particular memory use at compile time). In your example, I'd probably give up on pragma Pure, rather than give up on the named constant. I agree it's a bit annoying to have to give up one or the other. **************************************************************** From: Jeff Cousins Sent: Monday, September 5, 2016 10:54 AM Thanks Bob. ****************************************************************