!standard 3.08(12) 03-09-17 AC95-00081/01 !class amendment 03-09-17 !status received no action 03-09-17 !status received 03-09-13 !subject Components of an array type !summary !appendix !topic Proposal for a "(null array)" aggregate !reference RM95-4.3.3(2) !from Niklas Holsti 03-09-26 !keywords null arrays, array aggregates, private types !discussion Summary The expression '(null array)' should be allowed as an array aggregate and understood to mean an array of the type and dimensions expected in the context, with null index ranges. Existing similar constructs 1. '(null record)' for record aggregates with no components. 2. The expression "" for null strings. Expected impact on compilers Mainly syntactic sugar. Possibly a new place where overloading resolution is needed, but then the existing array-aggregate notations can also include overloaded parts and need resolution. Motivation Currently, a null array aggregate must be written with an explicit specification of the null index range and the value of the non-existent array component. For example, given type Vector_Type is array (Positive range <>) of Float; a null Vector_Type aggregate can be written as (1 .. 0 => 0.0) The drawbacks of this are: a) The index range is usually irrelevant, but must be given. b) The component value is certainly irrelevant, but must be given. Point (b) is particularly troublesome when the component type is a private type or a private formal generic parameter. Examples follow. Example 1: An array with a private component type. Assume the following package declaration: package Secrets is type Secret is private; type Secret_List is array (Positive range <>) of Secret; procedure Publish (My_Secrets : in Secret_List); private ... end Secrets; A client of Secrets that wants to publish an empty list of secrets must currently declare a dummy variable with an apparently undefined initial value and probably irrelevant index bounds: Null_List : Secret_List (1 .. 0); ... Publish (My_Secrets => Null_List); The proposal would allow simply Publish (My_Secrets => (null array)); which gets rid of the irrelevant index bounds 1 .. 0 and the apparent undefined value of the Null_List variable, and their potential to confuse the human reader and analysis tools. In the current standard, the provider of the private type may try to help its clients to create empty lists of secrets by defining a dummy constant secret value: package Secrets is ... No_Secret : constant Secret; ... private ... end Secrets Then, a client can publish an empty secrets list by Publish (My_Secrets => (1 .. 0 => No_Secret)); However, in the private part of the Secrets package declaration there must be a definition of No_Secret, of the form No_Secret : constant Secret := ; The is often an aggregate, and often this aggregate uses private types defined in other packages, forcing also these packages to provide dummy constants of these types, etc. The contagion spreads... Example 2: Formal generic type parameter Assume the following declaration of a package that implements flexible but bounded one-dimensional arrays, generic in the index type, component type and a normal (fixed-length) array type: generic type Index is (<>); type Component is private; type Vector is array (Index range <>) of Component; package Bounded_Vectors is type Bounded_Vector (Max_Length : Natural) is private; ... function To_Vector (Item : Bounded_Vector) return Vector; -- Converts the bounded vector to an ordinary vector. ... end Bounded_Vectors; Depending on the services provided in the package, there may be several places in the package body where a null Vector is needed, but again a null array aggregate cannot be written because it needs to have a dummy Component value, which is not available. The body must resort to apparently undefined null Vector variables, as in Example 1. If a new formal parameter for a dummy Component is added to the generic formals, the instantiation must provide a concrete value. If the type is actually private even at the instantiation point, or contains private components, the contagion spreads as in Example 1. Minor things The qualified form Some_Array_Type'(null array) should also be allowed. The issue of multi-dimensional arrays may need more thought. It seems more likely that the actual index ranges are significant for multi-dimensional null arrays than for single-dimensional null arrays; it may be significant to know which dimensions are null ranges. This can be expressed by the ordinary aggregate notation. The '(null array)' notation should be usable as a subaggregate, which allows the index range of the "top" dimensions to be specified. For example, a two-dimensional array aggregate with the first index range 3 .. 7 and the second index range null could be expressed as (3 .. 7 => (null array)) The analogous aggregate with the first index range null and the second index range 3 .. 7 cannot be expressed with the '(null array)' form, but has to be written in the currently accepted form and must specify both index ranges and a dummy component value. Potential problems 1. Although the index range of a null array is usually irrelevant to the application program, clearly '(null array)' must have some First and Last attributes. What should they be? Can this be solved in the same way as for an array aggregate in positional notation? 2. If the index type contains only a single value (for example, an enumeration with a single literal) it is not clear to me if null arrays can exist. Perhaps '(null array)' should be illegal or cause a bounded error in such cases. **************************************************************** From: Adam Beneschan Sent: Friday, September 26, 2003 3:08 PM > !topic Proposal for a "(null array)" aggregate > !reference RM95-4.3.3(2) > !from Niklas Holsti 03-09-26 > !keywords null arrays, array aggregates, private types > !discussion > > Summary > > The expression '(null array)' should be allowed as an array aggregate > and understood to mean an array of the type and dimensions expected > in the context, with null index ranges. It seems to me that this proposal has come up before, possibly before the Ada 95 standard was written, and was rejected. Personally, I think it's a good idea. I do find myself writing things like (1 .. 0 => blah-blah-blah) often, or defining a *variable* with a null range (which I can't define as a constant, even though it is a constant), and it seems silly. > Potential problems > > 1. Although the index range of a null array is usually irrelevant > to the application program, clearly '(null array)' must have > some First and Last attributes. What should they be? Can this > be solved in the same way as for an array aggregate in > positional notation? It probably can be solved in the same way as for the null string literal. For string literals, 4.2(10) says "The bounds of this array value are determined according to the rules for positional_array_- aggregates (see 4.3.3), except that for a null string literal, the upper bound is the predecessor of the lower bound. 4.3.3(26) says that in such a case, the lower bound is "that of the corresponding index range in the applicable index constraint, if defined, or that of the corresponding index subtype, if not". The index range of a null array could be determined in the same way. (If (null array) is allowed to refer to an entire multi-dimensional array, this would apply to each index range.) The fly in the ointment here is that it doesn't handle cases in which the lower bound of the index subtype has no predecessor. In fact, this is already the case with string literals: procedure Test89 is type Str is array (Integer range <>) of Character; procedure Proc (S : Str) is begin ... end Proc; begin Proc (""); end Test89; This program is illegal, because for the array represented by the null string literal, the language rules say the lower bound is Integer'First and the upper bound is the predecessor of the lower bound, which does not exist. (See also AI95-138.) This feature is unlikely to cause a problem for string literals, since the predefined String type has an index range of Positive. However, it would cause serious problems for a (null array) type, since it would be much more common to use this for an array whose index subtype is Integer (or some other integer type) or an enumeration type. If (null array) is added to the language, I'd propose modifying 4.3.3(26) so that if there is no applicable index constraint, the lower bound is that of the corresponding index subtype, except that in the case of a null array aggregate or null string literal, if the lower bound of the corresponding index subtype has no predecessor, then the lower bound of the aggregate is the *successor* of the lower bound of the corresponding index subtype. If, in this case, the lower bound has no successor, Constraint_Error would be raised, as specified in 3.5(22). (We could make 4.9(34) apply too, but we'd have to modify the rest of 4.9 to indicate when (null array) would be considered a "static expression".) This would take care of the next issue: > 2. If the index type contains only a single value (for example, > an enumeration with a single literal) it is not clear to me > if null arrays can exist. Perhaps '(null array)' should be > illegal or cause a bounded error in such cases. More likely, "should be illegal or cause Constraint_Error to be raised". **************************************************************** From: Randy Brukardt Sent: Monday, September 29, 2003 7:55 PM AI-287 gives us <> to mean the default value of a component. So (1..0 => <>) is a null array. It's a minor pain to look up the index subtype (but I usually just use 1..0 and see if the compiler chokes), but it's not that big of a deal. The alternative is writing a number of pages of RM rules to make these useful (and then having people confused by the rules, whatever they are). Hard to say if it is worth it. **************************************************************** From: Tucker Taft Sent: Monday, September 29, 2003 8:16 PM Good point. That seems to answer the need for a null array adequately. Interestingly, "(null record)" can presumably be represented with "(others => <>)" obviating the need for the special "(null record)" syntax as well. ****************************************************************