Version 1.4 of ais/ai-00299.txt

Unformatted version of ais/ai-00299.txt version 1.4
Other versions for file ais/ai-00299.txt

!standard 8.5.5 (2)          02-09-25 AI95-00299/02
!standard 12.4 (6)
!standard 12.5 (2)
!standard 12.7 (2)
!class amendment 02-06-12
!status No Action (8-1-1) 02-10-11
!status work item 02-06-12
!status received 02-06-12
!priority Medium
!difficulty Medium
!subject Defaults for generic formal parameters
!summary
The syntax of generic formal type, package, and "in out" object parameters are modified to permit default expressions.
!problem
Ada 95 does not have defaults for generic formal types or packages. While not a serious problem (users can always be forced to supply explicit values for all parameters), it is sometimes a nuisance and unnecessarily complicates some generic instantiations. Allowing more kinds of defaults for generic formal parameters can significantly ease the use of generic units.
!proposal
Defaults for generic formal types ---------------------------------
12.5(2) is modified to read
formal_type_declaration ::= type defining_identifier [discriminant_part] is formal_type_definition [else use default_subtype_mark];
The optional "else use subtype_mark" defines a default type to be used if an instantiation does not explicitly provide an actual for that parameter. 12.3(7 and 10) are modified to include default_subtype_mark as an option for missing parameter associations. (Note: "default_" is in italics in default_subtype_mark.) The subtype denoted by default_subtype_mark must fulfill all the constraints/rules as if it occurred as a generic actual in a generic parameter association.
Defaults for generic formal packages ------------------------------------
12.7 (2) is modified to read
formal_package_declaration ::= with package defining_identifier is new generic_package_name formal_actual_part [else use default_package_name];
The optional "else use package_name" defines a default package to be used if an instantiation does not explicitly provide an actual for that parameter. 12.3(7 and 10) are modified to include default_package_name as an option for missing parameter associations. (Note: "default_package_" is in italics in default_package_name.) The package denoted by default_package_name must be an instantiation of the generic package denoted by generic_package_name such that it fulfils the constraints imposed by the formal_actual_part.
Defaults for generic formal "in out" objects --------------------------------------------
It is proposed to delete paragraph 12.4(6). This will allow generic formal "in out" objects to have default expressions.
!discussion
The basic idea behind these changes is to allow all types of generic parameters to have defaults. Currently, only subprograms and 'in' objects may have a default value. However, the benefits of default parameters can exist for any kind of parameter.
All of these changes aim at making generic instantiations simpler to write, or rather, to give designers of generic units the means to design their units such that instantiations can be made simpler than today. It is often possible to supply reasonable default values for some of the entities to which the above proposal applies.
The syntax for default types is hard to define. 'Else use' was selected because a default type is an alternative to specifying an actual type. We also considered using a new keyword ('default'), the assignment symbol (':='), and various other combinations of existing reserved words ("use", "until others", "else"). "Use" is unacceptable because adding a semicolon would make another syntactically legal program. All of the others would be OK, but (except for "else") don't have the right flavor. For instance, ":=" seems to imply copying a type (which can't happen).
Defaults would have proven useful in the development of a library of container abstractions. A short discussion on comp.lang.ada revealed that several developers of container libraries have come across these issues and perceive them as shortcomings of Ada 95.
!example
An example for defaults for generic formal types ------------------------------------------------
Consider a list container with an operation returning the number of items currently in the list.
generic type Item_Type is private; with function "=" (L, R : in Item_Type) return Boolean; package Lists is
type List is private;
procedure Append (L : in out List; Item : in Item_Type);
function Length (L : in List) return Natural;
-- ... other operations private
type Node; type Link is access all Node; type Node is record Data : Item_Type; Next, Prev : Link; end record;
type List is new Ada.Finalization.Controlled with record N : Natural := 0; Head, Tail : Link; end record;
-- .. more stuff
end Lists;
All operations would maintain L.N, e.g. Append would add 1. When this was discussed on comp.lang.ada, some people argued that if one has lists of oranges and lists of apples, these should be counted using different types to avoid inadvertantly adding apple counts and orange counts. Hence the interface should be modified:
generic type Item_Type is private; type Item_Count is range <>; -- Must include zero. with function "=" (L, R : in Item_Type) return Boolean; package Lists is
-- ... as above, except:
function Length (L : in List) return Item_Count;
private
type List is new Ada.Finalization.Controlled with record N : Item_Count'Base := 0; Head, Tail : Link; end record;
end Lists;
Well, clearly not everybody agrees with that, and some people don't care, and some may say "well, Item_Count has that funny requirement that zero be included, so let's use Natural", so in a general container package, it might well make sense to provide a default (namely Natural) for the Item_Count type. With that, the generic package could cater for both styles, at no extra cost:
generic type Item_Type is private; type Item_Count is range <> else use Natural; -- New syntax. with function "=" (L, R : in Item_Type) return Boolean; package Lists is
...
end Lists;
An example for defaults for generic formal packages ---------------------------------------------------
Consider a hash table container abstraction using a signature package for the key type:
generic type Key_Type (<>) is private; with function Hash (Key : in Key_Type) return Natural; with function "=" (L, R : in Key_Type) return Boolean is <>; package Hashable is -- Signature package. end Hashable;
generic with package Keys is new Hashable (<>); type Item_Type (<>) is private; Initial_Default_Size : Positive := 23; package Hash_Tables is
type Hash_Table is private;
procedure Insert (Table : in out Hash_Table; Key : in Keys.Key_Type; Item : in Item_Type);
-- ... Other operations on hash tables
end Hash_Tables;
Then, one could get a package for hash tables with strings as keys as follows:
with Hash_Support; package String_Keys is new Hashable (Key_Type => String, Hash => Hash_Support.Hash_String);
generic with package Keys is new Hashable (<>) else use String_Keys; -- New syntax. type Item_Type (<>) is private; Initial_Default_Size : Positive := 23; package String_Hash_Tables is package Table is Hash_Tables (Keys, Item_Type, Initial_Default_Size); -- Probably would use renames here to make the contents directly visible. end String_Hash_Tables;
with the same instantiations for finally getting concrete hash tables:
package My_Hash_Tables is new String_Hash_Tables (Item_Type => My_Data);
package My_Other_Hash_Tables is new String_Hash_Tables (Item_Type => My_Other_Data);
An example for defaults for generic formal "in out" objects -----------------------------------------------------------
The motivating example for default values for generic formal "in out" objects is the storage pool parameter often found in container libraries:
generic type Item_Type is private; with function "=" (L, R : in Item_Type) return Boolean is <>; Pool : in out System.Storage.Root_Storage_Pool'Class; package Lists is
type List is private;
-- Operations on lists...
private
type Node; type Link is access all Node; for Link'Storage_Pool use Pool;
type Node is record Data : Item_Type; Next, Prev : Link; end record;
type List is new Ada.Finalization.Controlled with record Head, Tail : Link; end record;
end Lists;
Many users just don't care about storage pools (or even don't know what they are be good for). Advanced users, however, may well want to specify the pool in which the list should allocate its nodes, hence adding the pool as a generic formal parameter clearly makes sense. Unfortunately, it confuses less advanced users (and generally complicates instantiation in those cases where one really doesn't care).
If one could provide a default value for "Pool", this confusion or complication could be avoided: we could simply declare the package as
generic type Item_Type is private; with function "=" (L, R : in Item_Type) return Boolean is <>; Pool : in out System.Storage.Root_Storage_Pool'Class := The_Default_Pool; package Lists is ...
[For this example, we won't define what "The_Default_Pool" actually might be. For many implementations, a possible declaration might be a pre-written pool that just uses the standard pool of some arbitrary access type.]
With defaults for generic formal "in out" objects, an instantiation of this list package can be as simple as
package My_Lists is new Lists (My_Type);
Inexperienced users or users that chose not to care about storage pools can use the package without extra hassles, while experienced or concerned users still have the possibility to provide their own storage pool.
!ACATS test
!appendix

Editor's note: The original proposal was submitted by Thomas Wolf on
Wednesday, June 12, 2002. It was edited slightly, but otherwise used intact
as the initial draft of this AI.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, June 12, 2002  10:32 PM

Thanks for writing this, it saved me from having to do it. (I was going to
make a similar proposal when I got a round tuit.

> I cannot judge up-front how difficult or complex this would be to
> implement, but it appears to me to be relatively straight-forward: one
> just has to maintain info on what the defaults are, and in an instantiation,
> supply these defaults as the actuals for any generic formals that do not
> have explicit actuals. The whole instantiation process then should remain
> unchanged.

I'm concerned that the generic renaming would be significant work, as the
idea of "partial actual parts" would be new, and would require a new
mechanism to handle. Resolving these could be tricky, especially if they are
mixed positional and named parameters. I have to wonder if these would be
worth the work.

Otherwise, I don't think that there would be significant implementation
problem (if I did, I wouldn't have planned to introduce the idea).

I'm not sure about the syntax, but that just carries over from CLA.

****************************************************************

From the minutes of the 16th ARG meeting (Vienna, Austria):

Pascal argues that having such default just makes the code more obscure.

Tucker counters that we have defaults for other things, why should these be
limited to just objects and subprograms?

Tucker notes that use is a bad choice, because you could leave out a semicolon
and it would still be legal syntax. We tried hard to avoid that in Ada.

We could invent a new keyword ("default" is suggested). Another suggestion
(using existing keywords) is until others.

The generic renaming proposal can be implemented with a generic skin package.
It also appears very complex and messy to implement. We take a straw vote on
dropping the generic renames part of the proposal, which passes easily: 6-0-2.
This effectively means "No action" on part 3 of the proposal.

Pascal wonders if we should we support <> defaults on this? John replies that
<> defaults are a mess, we don't want to expand this further.

Tucker notes that it is odd that in out would allow a default here, and not in
subprograms. Randy comments that we could fix subprograms, too. There is no
support for that from the group. However, Pascal notes that in out formal
objects are really renames, the syntax is misleading.

We take a straw vote on keeping the AI alive. It passes, 4-2-2.

****************************************************************

Editor's notes:

The syntax of defaults for types is problematical. Here are some of the ideas
I considered:

generic
   type Item_Type is private;
   type Item_Count is range <> use Natural; -- Bad because
					    -- type Item_Count is range <>; use Natural;
					    -- is also legal.
package Lists is

generic
   type Item_Type is private;
   type Item_Count is range <> default Natural; -- 'Default' is a new keyword.
package Lists is

generic
   type Item_Type is private;
   type Item_Count is range <> := Natural;
package Lists is

generic
   type Item_Type is private;
   type Item_Count is range <> until others Natural;
package Lists is

generic
   type Item_Type is private;
   type Item_Count is range <> else Natural;
package Lists is

generic
   type Item_Type is private;
   type Item_Count is range <> else use Natural;
package Lists is

I've tested all of these in the Janus/Ada grammar using our LALR(1) parser
generator, and all of them work (no conflicts).

****************************************************************

Questions? Ask the ACAA Technical Agent