Version 1.27 of ais/ai-00230.txt
!standard 03.04.01(06) 05-09-30 AI95-00230/19
!standard 03.02.01(07)
!standard 03.02.01(08)
!standard 03.04.01(03)
!standard 03.04.01(10)
!standard 03.06(07)
!standard 03.06(22/1)
!standard 03.07(10)
!standard 03.07(27)
!standard 03.08(18/1)
!standard 03.10(12)
!standard 03.10(13)
!standard 03.10(17)
!standard 03.10.2(12)
!standard 03.10.2(34)
!standard 04.02(02)
!standard 04.02(07)
!standard 04.02(08)
!standard 04.05.02(07)
!standard 04.05.02(09)
!standard 04.06(13)
!standard 04.06(18)
!standard 04.06(49)
!standard 04.06(61)
!standard 08.05.01(02)
!standard 08.05.01(03)
!standard 08.05.01(06)
!standard 08.06(25)
!standard 13.7.2(25)
!standard 13.11(25)
!standard A.1(34)
!class amendment 00-04-13
!status Amendment 200Y 04-01-09
!status WG9 Approved 04-06-18
!status ARG Approved 8-0-4 03-12-12
!status work item 00-10-27
!status ARG Approved 10-0-0 03-10-03
!status work item 00-04-13
!status received 00-04-13
!priority Medium
!difficulty Hard
!subject Generalized use of anonymous access types
!summary
More general use of anonymous access types is proposed, to allow the
flexibility of implicit conversion and run-time accessibility checking
to be used in more contexts, including as components and in object renamings.
A separate AI (AI-00325) investigates using anonymous access
types as function result types.
NOTE: This AI is also related to AI-00231, which allows anonymous access
types to be specified to be access-to-constant as opposed to
access-to-variable, and to be either null-allowing or not null-allowing.
Without null-allowing anonymous access types, anonymous access components
are rather useless, so this proposal pretty much requires some version of
AI-231 to be approved.
!problem
The goal of this proposal is to resolve a problem encountered when creating Ada
packages to interface with code written in languages like Java, and in
using various common object-oriented programming paradigms.
In Java and other OO languages, types that are references to a subclass are
freely convertible to types that are references to a superclass. This implicit
conversion, which is always safe, significantly reduces the need for explicit
conversions when passing references as parameters.
With the current access type conversion rules in Ada 95, large numbers of
explicit conversions are required. This obscures the explicit conversions that
really do need attention, and makes the whole OO coding style seem more
cumbersome in Ada than in other OO languages.
In addition to addressing the problem of minimizing unnecessary
explicit-yet-safe conversions, there is the related problem of
minimizing (named) "access type proliferation". This generally occurs
when, for one reason or another, an access type is not defined at the
point of the type declaration (e.g., with the existing "purity" rules, a
pure package would never declare any access types). Ultimately, if they
need an access type, users of the type end up declaring their own
"personal" access type, creating yet more need for unnecessary
conversions.
There are two important technical problems that need to be addressed by
any solution:
Because Ada has local access types, there needs to be a way to remember
the accessibility level of the object designated by a reference across
certain operations, including possibly function return (see AI-00325).
Because Ada has multiple storage pools, it is important that an
allocator of an anonymous access type allocates from an appropriate
storage pool.
!proposal
The "access_definition" syntactic category (see 3.10(6); also see AI-00231) is
permitted in more places than just as formal parameters and discriminants. In
addition to the current places (parameters of mode in and discriminants of
limited types) it is permitted in object renaming declarations, component
definitions, and for discriminants of nonlimited types. The type associated
with the type definition is an anonymous access type, which permits
implicit conversions from other access types with appropriately compatible
designated subtypes (as defined by 4.6(13-17)).
The accessibility level of an anonymous access type is determined at the
time when the access_definition is elaborated. The general accessibility
level "philosophy" is:
a) For an access object that cannot be altered during its lifetime (parameter
of mode in, discriminant of a limited type), its level may be determined by the
accessibility level of its initial value or enclosing object. In addition, a
renaming inherits the accessibility level from the renamed/actual object.
b) For others (i.e. other kinds of components) the accessibility level
must be determined by the level of its declaration. This is necessary
to simplify implementation and to avoid dangling references when an
access object is updated while being "viewed" at a deeper level than it
truly is (which is always permitted by the current accessibility
checking rules).
Applying this general philosophy to the specific cases means that for a
renaming, the level is the same as the level of the type of the
renamed object. For a component definition or a discriminant of a
nonlimited type, the level is the same as that of the enclosing
composite type. As in the current language, IN parameters take their
level from the initial value, and discriminants of limited types take
their level from the enclosing composite object (as opposed to
enclosing type).
There is a special predefined equality (and matching inequality) operator
declared in package Standard which requires at least one of the parameters to
be of an anonymous access type, and the other to be convertible to that
anonymous access type. This implies the addition of the type universal_access.
Having added this type, it makes sense to change the literal NULL to be of this
type as well, for symmetry with numeric literals, and to avoid the need
for a preference rule in resolving the type of "null" when using the
universal_access equality operators.
The storage pool to be used for an allocator of an anonymous access type
is determined by the context in which it appears:
a) As the value for a parameter of mode in, an anonymous storage pool whose
storage is reclaimed when the subprogram returns;
b) As the initial value for a discriminant of a limited type, either:
i) the same storage pool as used for the enclosing object
if it is also created by an allocator, or
ii) an anonymous storage pool whose storage is
reclaimed when the enclosing object's scope ends.
c) As the initial value for a component other than a discriminant of
a limited type, a standard storage pool similar to that which would be used
for a named access type declared at the same level as the enclosing composite
type.
!wording
Delete "(including a parameter or a discriminant)" from 3.2.1(7).
Change 3.2.1(8) as follows:
A named type that is declared by a full_type_declaration,
or an anonymous type that is defined by {an access_definition or} as part
of declaring an object of the type, is called a full type. ...
Change 3.4.1(3) as follows:
Every type is either a specific type, a class-wide type, or a universal type.
A specific type is one defined by a type_declaration, a
formal_type_declaration, or a full type definition embedded in [a declaration
for an object]{another construct}. Class-wide and universal types are
implicitly defined, to act as representatives for an entire class of types,
as follows:
Change 3.4.1(6) as follows:
Universal Types
Universal types are defined for (and belong to) the integer, real, [and]
fixed point{, and access} classes, and are referred to in this standard
as respectively, universal_integer, universal_real, [and]
universal_fixed{, and universal_access}. These are analogous to
class-wide types for these language-defined {elementary}[numeric] classes.
As with class-wide types, if a formal parameter is of a universal type,
then an actual parameter of any type in the corresponding
class is acceptable. In addition, a value of a universal type (including
an integer or real numeric_literal{, or the literal @b<null>}) is
``universal'' in that it is acceptable where some particular type in the
class is expected (see 8.6).
Change 3.4.1(10) as follows:
... Similarly, the {numeric} universal types are defined to be
descendants of the root types of their classes. ...
Change 3.6(7) as follows:
component_definition ::= [aliased] subtype_indication | access_definition
Change 3.6(22/1) to add "or access_definition":
... The elaboration of a component_definition in an
array_type_definition consists of the elaboration of the
subtype_indication {or access_definition}. ...
Eliminate paragraph 3.7(10) (which allows access discriminants only
on limited types).
Change 3.7(27) as follows:
{For an access discriminant of a limited type, its} [An]
access_definition is elaborated when the value of [a corresponding]
{the} access discriminant is defined, either
by evaluation of its default_expresssion or by elaboration of a
discriminant_constraint. {For an access discriminant of a nonlimited
type, its access_definition is elaborated when the full_type_declaration
with the known_discriminant_part is elaborated.} The elaboration of
an access_definition ...
Change paragraph 3.8(18/1) as follows:
... For the elaboration of a component_definition of a
component_declaration or the discrete_subtype_definition of an
entry_declaration for an entry family (see 9.5.2), {if the component
subtype is defined by an access_definition or} if the constraint or
range of the subtype_indication or discrete_subtype_definition is not
a per-object constraint, then the {access_definition,}
subtype_indication{,} or discrete_subtype_definition is elaborated.
...
Change 3.10(12) and 3.10(17) to eliminate the list of places where
access_definition occurs. (In both cases, this text is not required,
and listing four places (access discriminant, access parameter,
component_definition, and object_renaming_declaration) is awkward. Besides,
we don't use text to list where subtype_indication [for instance] is allowed.)
Modify 3.10(13) as follows:
For each [(named)] access type, {other than a specific anonymous access
type,} there is [a literal null which has] a null access value designating
no entity at all. The null value of [a named] {an} access type is the ... in
the case of [a named] {an} access-to-object type, an allocator, which
returns ...
Note: This allows allocators of anonymous access types (which was intended
to be allowed in Ada 95, see 13.11(25)), and the literal null for
universal_access. AI-231 expands this further.
Add the following paragraph before 3.10.2(12):
The accessibility level of the anonymous access type defined by an
access_definition of an object_renaming_declaration is the same as that of
the renamed view.
Change paragraph 3.10.2(12) as follows:
The accessibility level of the anonymous access type {of a component
is that of the master that elaborated its access_definition. This
is the same as the level of the type whose definition encloses the
access_definition except in the case} of an access discriminant
{specified for a limited type, in which case it} is the same as that
of the containing object or associated constrained subtype.
AARM NOTE: For a type extension, for other than discriminants
of a limited type, the components inherited from
the parent have the same accessibility as they did in the parent;
those in the extension part have the accessibility determined
by the scope where the type extension is declared.
Similarly, the components of a derived untagged type other than
discriminants of a limited type have the same accessibility as they did
in the parent.
Change the end of the note 3.10.2(34) as follows:
... anonymous access types do not{, but they can use the predefined
equality operators for universal_access} (see 4.5.2).
Delete paragraph 4.2(2).
Replace paragraph 4.2(7) by:
A literal null shall not be of a specific anonymous access type, since such
types do not have a null value (see 3.10).
Note: AI-231 repeals this altogether.
Change paragraph 4.2(8) as follows:
... is of type universal_real. {The literal null is of type
universal_access.}
Add the following after paragraph 4.5.2(7):
The following additional equality operators for the universal_access type
are declared in package Standard for use with anonymous access types:
function "="(Left, Right : universal_access) return Boolean
function "/="(Left, Right : universal_access) return Boolean
Add the following after paragraph 4.5.2(9):
Name Resolution Rules
At least one of the operands of the equality operators for universal_access
shall be of a specific anonymous access type.
AARM Note: Universal access types do not count for the purposes of this
rule. Otherwise, equality expressions like (X = null) would be ambiguous for
normal access types.
Legality Rules
At least one of the operands of the equality operators for
universal_access shall be null, or both shall be
access-to-object types, or both shall be access-to-subprogram
types. Further:
* When both are access-to-object types, the
designated types shall be the same or one shall cover the
other, and if the designated types are elementary or array types,
then the designated subtypes shall statically match;
* When both are access-to-subprogram types,
the designated profiles shall be subtype conformant.
Change paragraph 4.6(13) as follows:
{If the target type is universal_access, then the operand type shall be an
access type.} If the target type is a general access{-to-object} type, then
the operand type shall be {universal_access or} an access-to-object type.
Further{, if the operand type is not universal_access}:
Add before 4.6(18):
If the target type is a pool-specific access-to-object type, then
the operand type shall be universal_access.
Change paragraph 4.6(18) as follows:
If the target type is an access-to-subprogram type, then the operand type
shall be {universal_access or} an access-to-subprogram type. Further{, if
the operand type is not universal_access}:
Change paragraph 4.6(49) as follows:
* If the target type is a[n] {specific }anonymous access type, a check is
made that the value of the operand is not null; if the target type is not a
specific anonymous access type, then the result is null if the operand value
is null.
Change paragraph 4.6(61) as follows:
22 A ramification of the overload resolution rules is that the operand of an
(explicit) type_conversion cannot be [the literal null, ]an allocator, an
aggregate, a string_literal, a character_literal, or an attribute_reference
for an Access or Unchecked_Access attribute. Similarly, such an expression
enclosed by parentheses is not allowed. A qualified_expression (see 4.7) can
be used instead of such a type_conversion.
Change paragraph 8.5.1(2) as follows:
object_renaming_declaration ::=
defining_identifier : subtype_mark renames object_name;
| defining_identifier : access_definition renames object_name;
Change paragraph 8.5.1(3) as follows:
The type of the object_name shall resolve to the type determined by
the subtype_mark{, or in the case where the type is defined by an
access_definition, to a specific anonymous access type whose designated type
is the same as that of the access_definition}.
NOTE: If AI-231 is adopted, then 8.5.1(4) should include a
legality rule that requires the access_definition to be
access-to-constant if and only if the renamed object is
access-to-constant. This is type-specific information, which is
included in a renaming declaration.
Change paragraph 8.5.1(6) as follows:
... any constraint implied by the subtype_mark {or access_definition}
of the object_renaming_declaration is ignored.
Modify paragraph 8.6(25):
...when T is a[n] {specific} anonymous access type ...
Remove parenthetical remark from 13.7.2(5) [null has type universal_access now].
Replace paragraph 13.11(25) by:
The storage pool used for an allocator of an anonymous
access type should be determined as follows:
* If the allocator is initializing an access discriminant of an object
of a limited type, and the discriminant is itself a subcomponent of an
object being created by an outer allocator, then the storage pool used
for the outer allocator should also be used for the allocator
initializing the access discriminant;
* For other access discriminants and access parameters, the storage pool
should be created at the point of the allocator, and be reclaimed when
the allocated object becomes inaccessible;
* Otherwise, a default storage pool should be created at
the point where the anonymous access type is elaborated; such a
storage pool need not support deallocation of individual objects.
AARM: Delete the first sentence of 13.11(17.c); it isn't true even in Ada 95.
Add after A.1(34):
-- The type universal_access is predefined.
-- The following equality operators are predefined:
function "=" (Left, Right: universal_access) return Boolean;
function "/=" (Left, Right: universal_access) return Boolean;
!example
type Obj is record
M : Integer;
Next : access Obj;
end record;
procedure Make_Cycle(X : access Obj) is
--
Next : access Obj renames X.Next;
begin
Next := new Obj(M => 3, Next => X); --
end Make_Cycle;
package P is
--
type T is ...
type Rec(D : access String := new String'("")) is record
F : access T; --
--
--
G : access T'Class := new T;
end record;
R : Rec := (D => new String'("Hello"), F => new T, G => new T);
Y : access String renames R.D;
function Fun(X : access Rec) return Integer;
end P;
package body P is
function Fun(X : access Rec) return Integer
Disc : access String renames X.D;
begin
return 123;
end Fun;
end P;
!discussion
In an object-oriented program, it is desirable to be able to use any descendant
of a root type in a context that only depends on the properties of the root
type. This principle is sometimes called "substitutability".
This is supported in Ada 95 by use of T'Class as a parameter type. However,
access types are used heavily in object-oriented systems, because of the
unknown size requirements when dealing with a type hierarchy. The parameter
notation "access T'Class" supports access type substitutability, but only for
parameters. Furthermore, it doesn't handle potentially null values. Finally, it
cannot be used for record or array components (other than access
discriminants). [Note that the "null value" problem is solved in AI-231. We
will make no further mention of this problem; see AI-231 for more discussion
of this issue.]
Explicit access type conversions can be used to provide the desired
substitutability, but scattering type conversions around muddies the water,
and makes it harder to find the few type conversions that are really
significant.
This AI proposes the generalization of the use of anonymous access types, as
declared by an access_definition. It avoids any incompatibility issues by not
changing the implicit conversion rules for existing named access types.
This proposal grew out of a long discussion about the difficulties associated
with a "with access type" mechanism (originally part of AI-00217). The problems
encountered relate to issues such as "thin" versus "fat" access-to-array types,
conventions associated with access types, access subtypes, etc. Furthermore,
Erhard Ploedereder reported significant concerns among his students with the
excessive numbers of explicit conversions required to use Ada 95. This happens
when an actual parameter is of type access-to-T2'Class, and the formal
parameter is of type access-to-T1'Class.
This problem could be solved by allowing implicit conversion only to
access-to-class-wide types. However, the current access-type conversion rules
are based more on the general vs. pool-specific distinction. Also, the
mutually-recursive type problem need not involve tagged types at all. It would
seem unnatural to require the use of tagged and class-wide types just to get
the implicit conversion on named general access types that is already available
for all anonymous general access types.
We propose allowing anonymous access types in object renamings,
discriminants of non-limited types, and component definitions.
We handle updatable components by specifying that their accessibility
level is determined by the enclosing composite type. This provides the
advantages of implicit conversion, without needing run-time
accessibility levels for individual components.
We have split out issues relating to anonymous function result types
into a separate AI-00325, so this one can be evaluated without getting
bogged down in the implementation issues associated with function
returns.
Similarly, issues relating to supporting access-to-constant and
null-allowing anonymous access types are in AI-00231.
IMPLEMENTATION ISSUES:
Object renaming declarations with access_definitions are no harder to
support than other renamings.
Component declarations with access_definitions have no special
accessibility level issues, because the level is determined just like a
named access type.
OTHER ALTERNATIVES CONSIDERED:
There was much discussion about something like "T'Access" being an
implicitly declared access type, similar to T'Class and T'Base, associated
with every type T. There was also investigation into a restricted
version of that in the form of T'Class_Access, which would be
an implicitly declared access-to-T'Class. The latter was rejected
as being too limiting, since access type proliferation occurs with
non-tagged types as well.
The more general version of T'Access was dropped because:
a) we already have anonymous access types, so it is not clear
we need two different notations for them.
b) AI-00231 includes proposals to allow access-to-constant
and null-allowing and non-null-allowing anonymous access types
in the existing contexts (on parameters and discriminants), and crafting
attribute identifiers to handle all combinations of these capabilities
would seem to be unwise. The access-to-constant capability
seems even more important for the wider usage we are
considering in this proposal.
c) The accessibility level of T'Access was presumed to be
the same as that of T. This could be limiting in various
ways, and in particular you couldn't safely convert to T'Access
from some potentially local access type.
d) Implementations which materialize all implicit types would have problems,
as there is no limit to the types that could be constructed (T'Access'Access,
T'Access'Access'Access, etc.)
We considered allowing anonymous access types in stand-alone
variable declarations. However the general philosophy for accessibility
levels (described above in the proposal section) would force
them to have a level determined by their declaration rather than initial
value. This might create confusion when copying an access parameter into
a local variable and unintentionally losing the accessibility level
information. By only allowing renamings, and having
them preserve the accessibility level information, we avoid this
possible problem. Because allowing constants but not variables
introduced a non-orthogonality, we chose to allow renamings which can be
used in most cases where a constant would have been useful.
As an alternative, we considered allowing variables of an anonymous access type
to carry run-time accessibility levels across assignment
statements with an accompanying accessibility check as well to handle
up-level assignments. But this would totally change the model,
since in all other cases we have fully determined the accessibility level
at the point of the elaboration of the anonymous access type.
We also considered allowing generic formal objects of an anonymous
access type. However, this adds significantly to the complexity of the
proposal, with relatively little added benefit. Just supporting it for
in mode formal objects would be feasible, as it would be nearly identical
to the support required for in, but this would again not be
consistent.
We have decided not to allow named subtypes of anonymous access types, because
they seemed to create more problems than they solved, and are not needed
if we allow anonymous access types in component declarations.
!corrigendum 3.2.1(7)
Replace the paragraph:
A type defined by a type_declaration is a named type;
such a type has one or more nameable subtypes.
Certain other forms of declaration also include type
definitions as part of the declaration for an object (including a
parameter or a discriminant). The type defined by such
a declaration is anonymous — it has no nameable subtypes.
For explanatory purposes, this International Standard sometimes refers to
an anonymous type by a pseudo-name, written in italics, and
uses such pseudo-names at places where the syntax normally requires
an identifier. For a named type whose first subtype is T,
this International Standard sometimes refers to the type of T
as simply "the type T."
by:
A type defined by a type_declaration is a named type;
such a type has one or more nameable subtypes.
Certain other forms of declaration also include type
definitions as part of the declaration for an object. The type defined
by such a declaration is anonymous — it has no nameable subtypes.
For explanatory purposes, this International Standard sometimes refers to
an anonymous type by a pseudo-name, written in italics, and
uses such pseudo-names at places where the syntax normally requires
an identifier. For a named type whose first subtype is T,
this International Standard sometimes refers to the type of T
as simply "the type T".
!corrigendum 3.2.1(8)
Replace the paragraph:
A named type that is declared by a full_type_declaration,
or an anonymous type that is defined as part of declaring
an object of the type, is called a full type.
The type_definition, task_definition, protected_definition,
or access_definition that defines a full type is called
a full type definition.
Types declared by other forms of type_declaration are
not separate types; they are partial or incomplete views
of some full type.
by:
A named type that is declared by a full_type_declaration,
or an anonymous type that is defined by an access_deinition or
as part of declaring an object of the type, is called a full type.
The type_definition, task_definition, protected_definition,
or access_definition that defines a full type is called
a full type definition.
Types declared by other forms of type_declaration are
not separate types; they are partial or incomplete views
of some full type.
!corrigendum 3.4.1(3)
Replace the paragraph:
Every type is either a specific type, a class-wide type, or a
universal type. A specific type is one defined by a type_declaration,
a formal_type_declaration, or a full type definition embedded in a
declaration for an object. Class-wide and universal types are implicitly
defined, to act as representatives for an entire class of types, as follows:
by:
Every type is either a specific type, a class-wide type, or a
universal type. A specific type is one defined by a type_declaration,
a formal_type_declaration, or a full type definition embedded in
another construct. Class-wide and universal types are implicitly
defined, to act as representatives for an entire class of types, as follows:
!corrigendum 3.4.1(6)
Replace the paragraph:
- Universal types
-
Universal types are defined for (and belong to) the integer, real, and fixed
point classes, and are referred to in this standard as respectively,
universal_integer, universal_real, and universal_fixed. These are
analogous to class-wide types for these language-defined numeric classes. As
with class-wide types, if a formal parameter is of a universal type, then an
actual parameter of any type in the corresponding class is acceptable. In
addition, a value of a universal type (including an integer or real
numeric_literal) is ``universal'' in that it is acceptable where some
particular type in the class is expected (see 8.6).
by:
- Universal types
-
Universal types are defined for (and belong to) the integer, real, fixed point,
and access classes, and are referred to in this standard as respectively,
universal_integer, universal_real, universal_fixed, and
universal_access. These are analogous to class-wide types for these
language-defined elementary classes. As with class-wide types, if a formal
parameter is of a universal type, then an actual parameter of any type in the
corresponding
class is acceptable. In addition, a value of a universal type (including an
integer or real numeric_literal, or the literal null) is ``universal''
in that it is acceptable where some particular type in the class is
expected (see 8.6).
!corrigendum 3.4.1(10)
Replace the paragraph:
A specific type T2 is defined to be a descendant of a type T1 if
T2 is the same as T1, or if T2 is derived (directly or indirectly)
from T1. A class-wide type T2'Class is defined to be a descendant of
type T1 if T2 is a descendant of T1. Similarly, the universal types
are defined to be descendants of the root types of their classes. If a type
T2 is a descendant of a type T1, then T1 is called an ancestor
of T2. The ultimate ancestor of a type is the ancestor of the type that
is not a descendant of any other type.
by:
A specific type T2 is defined to be a descendant of a type T1 if
T2 is the same as T1, or if T2 is derived (directly or indirectly)
from T1. A class-wide type T2'Class is defined to be a descendant of
type T1 if T2 is a descendant of T1. Similarly, the numeric
universal types are defined to be descendants of the root types of their
classes. If a type T2 is a descendant of a type T1, then T1 is
called an ancestor of T2. The ultimate ancestor of a type is the
ancestor of the type that is not a descendant of any other type.
!corrigendum 3.6(7)
Replace the paragraph:
component_definition ::= [aliased] subtype_indication
by:
component_definition ::= [aliased] subtype_indication | access_definition
!corrigendum 3.6(22/1)
Replace the paragraph:
The elaboration of a discrete_subtype_definition that does not contain
any per-object expressions creates the discrete
subtype, and consists of the elaboration of the subtype_indication or the
evaluation of the range. The elaboration of a
discrete_subtype_definition that contains one or more per-object
expressions is defined in 3.8. The elaboration of a component_definition
in an array_type_definition consists of the elaboration of the
subtype_indication. The elaboration of any
discrete_subtype_definitions and the elaboration of
the component_definition are performed in an arbitrary order.
by:
The elaboration of a discrete_subtype_definition that does not contain
any per-object expressions creates the discrete
subtype, and consists of the elaboration of the subtype_indication or the
evaluation of the range. The elaboration of a
discrete_subtype_definition that contains one or more per-object
expressions is defined in 3.8. The elaboration of a component_definition
in an array_type_definition consists of the elaboration of the
subtype_indication or access_definition. The elaboration of any
discrete_subtype_definitions and the elaboration of
the component_definition are performed in an arbitrary order.
!corrigendum 3.7(10)
Delete the paragraph:
A discriminant_specification for an access discriminant shall appear only
in the declaration for a task or protected type, or for a type with the
reserved word limited in its (full) definition or in that of one of its
ancestors. In addition to the places where Legality Rules normally apply (see
12.3), this rule applies also in the private part of an instance of a generic
unit.
!corrigendum 3.7(27)
Replace the paragraph:
An access_definition is elaborated when the value of a corresponding
access discriminant is defined, either by evaluation of its
default_expression or by elaboration of a discriminant_constraint.
The elaboration of an access_definition creates the anonymous access
type. When the expression defining the access discriminant is evaluated, it is
converted to this anonymous access type (see 4.6).
by:
For an access discriminant of a limited type, its access_definition is
elaborated when the value of the access discriminant is defined, either
by evaluation of its default_expresssion or by elaboration of a
discriminant_constraint. For an access discriminant of a nonlimited
type, its access_definition is elaborated when the
full_type_declaration with the known_discriminant_part is elaborated.
The elaboration of an access_definition creates the anonymous access
type. When the expression defining the access discriminant is evaluated, it is
converted to this anonymous access type (see 4.6).
!corrigendum 3.8(18/1)
Replace the paragraph:
Within the definition of a composite type, if a component_definition or
discrete_subtype_definition (see 9.5.2) includes a name that denotes
a discriminant of the type, or that is an attribute_reference whose
prefix denotes the current instance of the type, the expression containing the
name is called a per-object expression, and the constraint or
range being defined is called a per-object constraint. For the
elaboration of a component_definition of a component_declaration or
the discrete_subtype_definition of an entry_declaration for an entry
family (see 9.5.2), if the constraint or range of the
subtype_indication or discrete_subtype_definition is not a per-object
constraint, then the subtype_indication or discrete_subtype_definition
is elaborated. On the other hand, if the constraint or range is a
per-object constraint, then the elaboration consists of the evaluation of any
included expression that is not part of a per-object expression. Each such
expression is evaluated once unless it is part of a named association in a
discriminant constraint, in which case it is evaluated once for each associated
discriminant.
by:
Within the definition of a composite type, if a component_definition or
discrete_subtype_definition (see 9.5.2) includes a name that denotes
a discriminant of the type, or that is an attribute_reference whose
prefix denotes the current instance of the type, the expression containing the
name is called a per-object expression, and the constraint or
range being defined is called a per-object constraint. For the
elaboration of a component_definition of a component_declaration or
the discrete_subtype_definition of an entry_declaration for an entry
family (see 9.5.2), if the component subtype is defined by an
access_definition or if the constraint or range of the
subtype_indication or discrete_subtype_definition is not a per-object
constraint, then the access_definition, subtype_indication, or
discrete_subtype_definition is elaborated. On the other hand, if the
constraint or range is a per-object constraint, then the elaboration
consists of the evaluation of any included expression that is not part of a
per-object expression. Each such expression is evaluated once unless it is part
of a named association in a discriminant constraint, in which case it is
evaluated once for each associated discriminant.
!corrigendum 3.10(12)
Replace the paragraph:
An access_definition defines an anonymous general access-to-variable type;
the subtype_mark denotes its designated subtype. An
access_definition is used in the specification of an access discriminant
(see 3.7) or an access parameter (see 6.1).
by:
An access_definition defines an anonymous general access-to-variable type;
the subtype_mark denotes its designated subtype.
!corrigendum 3.10(13)
Replace the paragraph:
For each (named) access type, there is a literal null which has a null access
value designating no entity at all. The null value of a named access type is
the default initial value of the type. Other values of an access type are
obtained by evaluating an attribute_reference for the Access or
Unchecked_Access attribute of an aliased view of an object or non-intrinsic
subprogram, or, in the case of a named access-to-object type, an allocator,
which returns an access value designating a newly created object (see 3.10.2).
by:
For each access type, other than a specific anonymous access type, there is a
null access value designating no entity at all. The null value of an access
type is the default initial value of the type. Other values of an access type
are obtained by evaluating an attribute_reference for the Access or
Unchecked_Access attribute of an aliased view of an object or non-intrinsic
subprogram, or, in the case of an access-to-object type, an allocator,
which returns an access value designating a newly created object (see 3.10.2).
!corrigendum 3.10(17)
Replace the paragraph:
The elaboration of an access_definition creates an anonymous general
access-to-variable type [(this happens as part of the initialization of an
access parameter or access discriminant)].
by:
The elaboration of an access_definition creates an anonymous general
access-to-variable type.
!corrigendum 3.10.2(12)
Replace the paragraph:
- The accessibility level of the anonymous access type of an access
discriminant is the same as that of the containing object or associated
constrained subtype.
by:
- The accessibility level of the anonymous access type defined by an
access_definition of an object_renaming_declaration is the same as
that of the renamed view.
- The accessibility level of the anonymous access type of a component
is that of the master that elaborated its access_definition. This
is the same as the level of the type whose definition encloses the
access_definition except in the case of an access discriminant
specified for a limited type, in which case it is the same as that
of the containing object or associated constrained subtype.
!corrigendum 3.10.2(34)
Replace the paragraph:
82 The predefined operations of an access type also include the
assignment operation, qualification, and membership tests. Explicit conversion
is allowed between general access types with matching designated subtypes;
explicit conversion is allowed between access-to-subprogram types with subtype
conformant profiles (see 4.6). Named access types have predefined equality
operators; anonymous access types do not (see 4.5.2).
by:
82 The predefined operations of an access type also include the
assignment operation, qualification, and membership tests. Explicit conversion
is allowed between general access types with matching designated subtypes;
explicit conversion is allowed between access-to-subprogram types with subtype
conformant profiles (see 4.6). Named access types have predefined equality
operators; anonymous access types do not, but they can use the predefined
equality operators for universal_access (see 4.5.2).
!corrigendum 4.2(2)
Delete the paragraph:
The expected type for a literal null shall be a single access type.
!corrigendum 4.2(7)
Replace the paragraph:
A literal null shall not be of an anonymous access type, since
such types do not have a null value (see 3.10).
by:
A literal null shall not be of a specific anonymous access type, since such
types do not have a null value (see 3.10).
!corrigendum 4.2(8)
Replace the paragraph:
An integer literal is of type universal_integer. A real literal is of type
universal_real.
by:
An integer literal is of type universal_integer. A real literal is of type
universal_real. The literal null is of type universal_access.
!corrigendum 4.5.2(7)
Insert after the paragraph:
function "=" (Left, Right : T) return Boolean
function "/="(Left, Right : T) return Boolean
the new paragraphs:
The following additional equality operators for the universal_access type
are declared in package Standard for use with anonymous access types:
function "=" (Left, Right : universal_access) return Boolean
function "/="(Left, Right : universal_access) return Boolean
!corrigendum 4.5.2(9)
Insert after the paragraph:
function "<" (Left, Right : T) return Boolean
function "<="(Left, Right : T) return Boolean
function ">" (Left, Right : T) return Boolean
function ">="(Left, Right : T) return Boolean
the new paragraphs:
Name Resolution Rules
At least one of the operands of the equality operators for universal_access
shall be of a specific anonymous access type.
Legality Rules
At least one of the operands of the equality operators for
universal_access shall be null, or both shall be
access-to-object types, or both shall be access-to-subprogram
types. Further:
- When both are access-to-object types, the
designated types shall be the same or one shall cover the
other, and if the designated types are elementary or array types,
then the designated subtypes shall statically match;
- When both are access-to-subprogram types,
the designated profiles shall be subtype conformant.
!corrigendum 4.6(13)
Replace the paragraph:
If the target type is a general access type, then the operand type shall be an
access-to-object type. Further:
by:
If the target type is universal_access, then the operand type shall be an
access type.
If the target type is a general access-to-object type, then
the operand type shall be universal_access or an access-to-object type.
Further, if the operand type is not universal_access:
!corrigendum 4.6(18)
Replace the paragraph:
If the target type is an access-to-subprogram type, then the operand type
shall be an access-to-subprogram type. Further:
by:
- If the target type is a pool-specific access-to-object type, then
the operand type shall be universal_access.
If the target type is an access-to-subprogram type, then the operand type
shall be universal_access or an access-to-subprogram type. Further, if
the operand type is not universal_access:
!corrigendum 4.6(49)
Replace the paragraph:
- If the target type is an anonymous access type, a check is made that
the value of the operand is not null; if the target is not an anonymous access
type, then the result is null if the operand value is null.
by:
- If the target type is a specific anonymous access type, a check is made
that the value of the operand is not null; if the target type is not a specific
anonymous access type, then the result is null if the operand value is null.
!corrigendum 4.6(61)
Replace the paragraph:
22 A ramification of the overload resolution rules is that the operand of an
(explicit) type_conversion cannot be the literal null, an allocator,
an aggregate, a string_literal, a character_literal, or an
attribute_reference for an Access or Unchecked_Access attribute.
Similarly, such an expression enclosed by parentheses is not allowed. A
qualified_expression (see 4.7) can be used instead of such a
type_conversion.
by:
22 A ramification of the overload resolution rules is that the operand of an
(explicit) type_conversion cannot be an allocator,
an aggregate, a string_literal, a character_literal, or an
attribute_reference for an Access or Unchecked_Access attribute.
Similarly, such an expression enclosed by parentheses is not allowed. A
qualified_expression (see 4.7) can be used instead of such a
type_conversion.
!corrigendum 8.5.1(2)
Replace the paragraph:
object_renaming_declaration ::=
defining_identifier : subtype_mark renames object_name;
by:
object_renaming_declaration ::=
defining_identifier : subtype_mark renames object_name;
| defining_identifier : access_definition renames object_name;
!corrigendum 8.5.1(3)
Replace the paragraph:
The type of the object_name shall resolve to the type determined by the
subtype_mark.
by:
The type of the object_name shall resolve to the type determined by
the subtype_mark, or in the case where the type is defined by an
access_definition, to a specific anonymous access type whose
designated type is the same as that of the access_definition.
!corrigendum 8.5.1(6)
Replace the paragraph:
An object_renaming_declaration declares a new view of the renamed object
whose properties are identical to those of the renamed view. Thus, the
properties of the renamed object are not affected by the
renaming_declaration. In particular, its value and whether or not it is a
constant are unaffected; similarly, the constraints that apply to an object are
not affected by renaming (any constraint implied by the subtype_mark of
the object_renaming_declaration is ignored).
by:
An object_renaming_declaration declares a new view of the renamed object
whose properties are identical to those of the renamed view. Thus, the
properties of the renamed object are not affected by the
renaming_declaration. In particular, its value and whether or not it is a
constant are unaffected; similarly, the constraints that apply to an object are
not affected by renaming (any constraint implied by the subtype_mark or
access_definition of the object_renaming_declaration is ignored).
!corrigendum 8.6(25)
Replace the paragraph:
- when T is an anonymous access type (see 3.10) with designated type
D, to an access-to-variable type whose designated type is D'Class or is
covered by D.
by:
- when T is a specific anonymous access type (see 3.10) with
designated type D, to an access-to-variable type whose designated type is
D'Class or is covered by D.
!corrigendum 13.7.2(5)
Replace the paragraph:
The To_Pointer and To_Address subprograms convert back and forth between values
of types Object_Pointer and Address. To_Pointer(X'Address) is equal to
X'Unchecked_Access for any X that allows Unchecked_Access.
To_Pointer(Null_Address) returns null. For other addresses, the behavior is
unspecified. To_Address(null) returns Null_Address (for null of the
appropriate type). To_Address(Y), where Y /= null, returns
Y.all'Address.
by:
The To_Pointer and To_Address subprograms convert back and forth between values
of types Object_Pointer and Address. To_Pointer(X'Address) is equal to
X'Unchecked_Access for any X that allows Unchecked_Access.
To_Pointer(Null_Address) returns null. For other addresses, the behavior is
unspecified. To_Address(null) returns Null_Address. To_Address(Y),
where Y /= null, returns Y.all'Address.
!corrigendum 13.11(25)
Replace the paragraph:
A storage pool for an anonymous access type should be created at the point of
an allocator for the type, and be reclaimed when the designated object becomes
inaccessible.
by:
The storage pool used for an allocator of an anonymous access type should
be determined as follows:
- If the allocator is initializing an access discriminant of an
object of a limited type, and the discriminant is itself a subcomponent of an
object being created by an outer allocator, then the storage pool used
for the outer allocator should also be used for the allocator
initializing the access discriminant;
- For other access discriminants and access parameters, the storage pool
should be created at the point of the allocator, and be reclaimed when
the allocated object becomes inaccessible;
- Otherwise, a default storage pool should be created at
the point where the anonymous access type is elaborated; such a
storage pool need not support deallocation of individual objects.
!corrigendum A.1(34)
Insert after the paragraph:
function "/" (Left : universal_fixed; Right : universal_fixed;)
return universal_fixed;
the new paragraphs:
-- The type universal_access is predefined.
-- The following equality operators are predefined:
function "=" (Left, Right: universal_access) return Boolean;
function "/=" (Left, Right: universal_access) return Boolean;
!ACATS test
Tests should be created to check on the implementation of this feature.
!appendix
Randy Brukardt 00-04-13
This proposal was split out of the "with type" proposal (AI-00217) in
April 2000. Some early conversation on this feature can be found in that
AI's appendix.
*************************************************************
From: Tucker Taft
Sent: Monday, April 03, 2000 5:29 PM
How about if we get an e-mail discussion going, then?
The major new idea in my revision of AI-230 is the attribute
on tagged types "'Class_Access". T'Class_Access is a type
that may be used as the type of a stand-alone object, record or
array component, parameter, etc. It is "universal" in the sense
that when the expected type is T'Class_Access, any access type
whose designated type is covered by T'Class may be used.
There would need to be an accessibility check that the source type has the
same accessibility level as type T. It would have "=" and "/=" operators,
and the "null" literal. Allocators would raise Storage_Error, because
the Storage_Size for T'Class_Access is defined to be 0.
Such an access type would very closely match the reference-type implicit
conversion semantics of Java and C++, providing "substitutability"
for access-to-tagged types in much the way that T'Class supports
substitutability for tagged types.
T'Class_Access would be permitted on incomplete tagged types (a new
category of incomplete types). I suppose we would also allow
T'Class_Access on plain old incomplete types, with the same provisos
as on T'Class (e.g. only in the same library unit and the full type must
be tagged).
T'Class_Access avoids some of the difficulties associated with the
more general T'Access proposal, since it doesn't need to worry, e.g., about
thin versus fat pointers, and loosens conversion rules only in
the place where they seem most critical, namely dealing with
conversions to access-to-'class types.
The hope is that when combined with "with type T is tagged;", T'Class_Access
will make bindings to Java-like languages much more straightforward both
to create and to use.
*************************************************************
From: Robert A Duff
Sent: Tuesday, April 04, 2000 10:46 AM
> How about if we get an e-mail discussion going, then?
I like the T'Class_Access idea.
But why not call it T'Access? But keep the rule that it's only for
tagged, and the designated type is T'Class. That is, I'm just
suggesting a name change. I don't see any benefit in the extra verbiage
"Class_". Ada is already verbose enough, compared to Pascal's perfectly
readable "^T" and C's somewhat ugly "T*".
I'm not against verbosity when it imparts useful information, so let's
not have a discussion of verbodity in general!
>...Allocators would raise Storage_Error, because
> the Storage_Size for T'Class_Access is defined to be 0.
Does this mean I can use T'Class_Access in a pragma-Pure package?
*************************************************************
From: Tucker Taft
Sent: Tuesday, April 04, 2000 11:44 AM
Robert A Duff wrote:
> But why not call it T'Access? But keep the rule that it's only for
> tagged, and the designated type is T'Class. That is, I'm just
> suggesting a name change. I don't see any benefit in the extra verbiage
> "Class_".
I think there is an important benefit. At least *I* would presume
that T'Access would be an access-to-T type rather than an access-to-T'Class
type. Also, T'Class_Access is clearly only appropriate for tagged
types, whereas T'Access seems like a perfectly reasonable thing to
allow for any kind of type.
> >...Allocators would raise Storage_Error, because
> > the Storage_Size for T'Class_Access is defined to be 0.
>
> Does this mean I can use T'Class_Access in a pragma-Pure package?
That was a possibility. If we allow access types
in pure packages, we need certain restrictions.
At a minimum, access types declared in pure packages should
have Storage_Size 0. Since access parameters and discriminants
are already allowed in pure packages, it seems unnecessary
to go any further. However, we would have to amend the
rules on shared passive packages to disallow not only the declaration
of access-to-classwide types, but also the declaration of library-level
objects of a type, or access types designating a type, with any
part being of an access-to-classwide type.
Alternatively, it might be easier to disallow T'Class_Access inside
a pure library unit, if T is library-level (or a formal type),
even though you could use T'Class_Access outside a pure library
unit, despite the fact that T was declared inside a pure library unit.
That seems more prudent for now. If we decide to allow
storage-size-zero access types in pure packages in general,
then we could examine allowing T'Class_Access there as well.
Conceptually, we could think of Pure_Pkg.T'Class_Access being implicitly
declared in a (virtual) impure child of Pure_Pkg, which is only visible
to impure packages that "with" Pure_Pkg.
*************************************************************
From: Robert A Duff
Sent: Tuesday, April 04, 2000 12:02 PM
> I think there is an important benefit. At least *I* would presume
> that T'Access would be an access-to-T type rather than an access-to-T'Class
> type. Also, T'Class_Access is clearly only appropriate for tagged
> types, whereas T'Access seems like a perfectly reasonable thing to
> allow for any kind of type.
But none of that is likely to cause bugs.
Another idea would be to call it T'Class'Access, presumably allowing:
type T is tagged...;
subtype S is T'Class;
... S'Access ...
I'm not particularly advocating that.
> That was a possibility. If we allow access types
> in pure packages, we need certain restrictions.
> At a minimum, access types declared in pure packages should
> have Storage_Size 0. Since access parameters and discriminants
> are already allowed in pure packages, it seems unnecessary
> to go any further. However, we would have to amend the
> rules on shared passive packages to disallow not only the declaration
> of access-to-classwide types, but also the declaration of library-level
> objects of a type, or access types designating a type, with any
> part being of an access-to-classwide type.
You realize this is a dangerous discussion. It's a side issue, but
discussing it makes the original proposal look more complicated. ;-)
> Alternatively, it might be easier to disallow T'Class_Access inside
> a pure library unit, if T is library-level (or a formal type),
> even though you could use T'Class_Access outside a pure library
> unit, despite the fact that T was declared inside a pure library unit.
I don't see the point of that. I want to declare self-referential data
structures in pure packages. Of course, the creation routines have to
be elsewhere (eg in an impure child).
> That seems more prudent for now. If we decide to allow
> storage-size-zero access types in pure packages in general,
> then we could examine allowing T'Class_Access there as well.
>
> Conceptually, we could think of Pure_Pkg.T'Class_Access being implicitly
> declared in a (virtual) impure child of Pure_Pkg, which is only visible
> to impure packages that "with" Pure_Pkg.
Sounds ugly to me. I don't like inventing all kinds of implicit junk
all over. I advocate allowing it in the pure package, unless we
actually have semantic problems with that. We already agreed that you
can't do alligators.
*************************************************************
From: Tucker Taft
Sent: Tuesday, April 04, 2000 1:16 PM
Robert A Duff wrote:
>
> > I think there is an important benefit. At least *I* would presume
> > that T'Access would be an access-to-T type rather than an access-to-T'Class
> > type. Also, T'Class_Access is clearly only appropriate for tagged
> > types, whereas T'Access seems like a perfectly reasonable thing to
> > allow for any kind of type.
>
> But none of that is likely to cause bugs.
It is bound to cause confusion, in my view. Also, we might
eventually want to allow T'Access as a generall anonymous access-to-T.
If we used T'Access to mean access-to-T'Class, we would have eliminated
that possibility.
> Another idea would be to call it T'Class'Access, presumably allowing:
>
> type T is tagged...;
> subtype S is T'Class;
> ... S'Access ...
>
> I'm not particularly advocating that.
That is where I started, but I rejected that because again it
implied more generality than was provided. Note that T'Class'Access
is the same number of characters as T'Class_Access ;-)
> ... I advocate allowing it in the pure package, unless we
> actually have semantic problems with that. We already agreed that you
> can't do alligators.
The semantic problems have to do with shared passive partitions, which
are allowed to depend on pure packages, but which are not allowed to
have access-to-class-wide objects, since they implicitly involve
pointers to code that is potentially not as long-lived as the
shared passive partition. I agree it is a side issue, but it is
a thorny one. Perhaps the right answer is to presume that shared
passive partitions need their own rules to prevent dangling references,
and not to try too hard to make the rules of pure library units
worry about them.
On the other hand, we do need some well defined criteria for deciding
what can go in a pure package. One goal is side-effect-freeness, but
with access parameters and access discriminants, that is pretty
much out the window. The other goal is ability to replicate freely
among different partitions, since it has no "state" of its own.
Perhaps the side-effect-freeness can be resurrected if we limit
ourselves to cases where the parameters have no access-type parts.
I suppose another way to say it is that the only side-effects are
through parameters and data accessible via access-type parts of
parameters. There is no variable "state" visible via up-level
references that could be altered. We should probably also disallow
the declaration of constants with any aliased parts, so the pure
package remains position independent, and hence freely replicable.
So I guess I am convinced -- force them to have storage size 0,
and allow them in pure packages. Similarly, we should allow
normal access-type declarations in pure packages, but with
the storage size implicitly zero, while disallowing constants
with aliased parts. Shared passive packages will
need some amended rules to deal with the allowance of
access types in pure packages.
*************************************************************
From: Gary Dismukes
Sent: Tuesday, April 04, 2000 2:11 PM
> It is bound to cause confusion, in my view. Also, we might
> eventually want to allow T'Access as a generall anonymous access-to-T.
> If we used T'Access to mean access-to-T'Class, we would have eliminated
> that possibility.
Tuck, can you comment on the reason for not generalizing
the implicit conversion capability to arbitrary designated
types? At the September meeting we were talking in terms
of an attribute T'univ_access which would allow implicit
conversions to any access-to-D where D covers T and
from any access-to-D where T covers D, but not restricted
to tagged types. It probably makes sense to restrict
the conversions so that it only goes towards one of these
special types, but what's the reason for limiting it
to class-wide types? Is it just because the main benefit
and anticipated use is for those, or is there some fundamental
difficulty with the generalization to other types? Or are
you just being conservative in your old age? ;-)
*************************************************************
From: Tucker Taft
Sent: Tuesday, April 04, 2000 2:59 PM
> Tuck, can you comment on the reason for not generalizing
> the implicit conversion capability to arbitrary designated
> types?
There were some concerns about access-to-unconstrained-array, and
whether it is thin or fat.
I suppose there would also be a lot of anonymous access types
popping up all over, with the associated "=" and "/=", if 'univ_access
applied to all types.
The minutes indicate there were some concerns about representation,
but I don't remember the details.
> ... Is it just because the main benefit
> and anticipated use is for those, or is there some fundamental
> difficulty with the generalization to other types? Or are
> you just being conservative in your old age? ;-)
These are all good reasons ;-)
Since this is really trying to help with Java interfacing
and "with type," the 'Class_Access seemed a smaller, more
manageable change.
I also think the proposed potentially-null anonymous access
parameter "access all T"/"access constant T" solves the
interfacing-to-C-pointer-parameter problems in a better way than
would a more general T'Univ_Access.
*************************************************************
From: Robert A Duff
Sent: Tuesday, April 04, 2000 5:15 PM
> The semantic problems have to do with shared passive partitions, which
> are allowed to depend on pure packages, but which are not allowed to
> have access-to-class-wide objects, since they implicitly involve
> pointers to code that is potentially not as long-lived as the
> shared passive partition. I agree it is a side issue, but it is
> a thorny one. Perhaps the right answer is to presume that shared
> passive partitions need their own rules to prevent dangling references,
> and not to try too hard to make the rules of pure library units
> worry about them.
Yes. They can have some extra rules.
> On the other hand, we do need some well defined criteria for deciding
> what can go in a pure package. One goal is side-effect-freeness, but
> with access parameters and access discriminants, that is pretty
> much out the window.
I thought the goal was to prevent silent side effects -- ie side effects
on globals, whereas side effects on parameters (or what they point to)
are OK.
>... The other goal is ability to replicate freely
> among different partitions, since it has no "state" of its own.
> Perhaps the side-effect-freeness can be resurrected if we limit
> ourselves to cases where the parameters have no access-type parts.
> I suppose another way to say it is that the only side-effects are
> through parameters and data accessible via access-type parts of
> parameters. There is no variable "state" visible via up-level
> references that could be altered. We should probably also disallow
> the declaration of constants with any aliased parts, so the pure
> package remains position independent, and hence freely replicable.
I'm not sure I understand that. Could you give an example?
> So I guess I am convinced ...
Cool. It's not easy to convince Tucker of something. Not because he's
stubborn, but because he's usually right. ;-)
>... -- force them to have storage size 0,
> and allow them in pure packages. Similarly, we should allow
> normal access-type declarations in pure packages, but with
> the storage size implicitly zero, while disallowing constants
> with aliased parts. Shared passive packages will
> need some amended rules to deal with the allowance of
> access types in pure packages.
Sounds good to me.
*************************************************************
From: Robert A Duff
Sent: Tuesday, April 04, 2000 5:24 PM
> There were some concerns about access-to-unconstrained-array, and
> whether it is thin or fat.
I think Pascal raised a concern about a 64-bit machine, where it might
make sense to have both 32-bit and 64-bit access types, where the user
chooses by writing a rep clause.
Pascal?
> Since this is really trying to help with Java interfacing
> and "with type," the 'Class_Access seemed a smaller, more
> manageable change.
I see it as a general feature. I think it's a serious flaw in Ada 95
that you have to write all kinds of type conversions that are perfectly
safe. A type conversion ought to be a red flag, saying "I'm
deliberately violating the type rules", but that doesn't work if you
have to constantly "cry wolf". You can convert implicitly from T2 to
T1'Class (where T2 is new T1) and you ought to be able to do the
analogous thing for pointer-to-T2 and pointer-to-T1'Class. The
'Class_Access idea solves that.
> I also think the proposed potentially-null anonymous access
> parameter "access all T"/"access constant T" solves the
> interfacing-to-C-pointer-parameter problems in a better way than
> would a more general T'Univ_Access.
Agreed.
*************************************************************
From: Robert Dewar
Sent: Wednesday, April 05, 2000 1:09 PM
<<I think Pascal raised a concern about a 64-bit machine, where it might
make sense to have both 32-bit and 64-bit access types, where the user
chooses by writing a rep clause.>>
VMS being an obvious example, just so that this does not seem to be
only a theoretical concern.
*************************************************************
From: Pascal Leroy
Sent: Thursday, April 06, 2000 4:22 AM
Yes, any proposal which assumes that "all accesses look the same" is flawed.
The 32-vs.-64-bit access types is not a theoretical issue, we do just that on
Alpha because people don't want to pay for 64-bit pointers when their data
structures are much smaller than 2Gb.
*************************************************************
From: Christoph Grein
Sent: Monday, May 08, 2000 11:45 PM
Subject: [Ada-Comment] Predefined Access Types
!topic Predefined Access Types
!reference RM95-A.4.5(7,8), RM95-3.6.3, RM95-3.10
!from Christoph Grein 2000-05-09
!keywords access types, String_Access
!discussion
The type String_Access and corresponding function Free in A.4.5(7,8) seem
misplaced in this package. They are not used there at all.
In the light of the fact that when strings are handled, very often (I would even
say, virtually always) an access type is also needed even if package
Ada.Strings.Unbounded is not used, I would propose to shift these declarations
to the place where type String is defined, 3.6.3. [And correspondingly for wide
strings A.4.7.]
This removes programmers' need to declare their own access types to strings all
over the place.
In a step further, I would propose a new 'Access attribute for types:
Given any type T, T'Access would denote the following predefined general access
type
type T'Access is access all T;
This would be implicitly defined where T is defined. Correspondingly also the
type T'Class'Access would be predefined where 'Class is defined.
[There would have to be rule to prevent recursion: Since T'Access is also a
type, T'Access'Access and so on should be ruled out as being predefined.]
If this is accepted, the type String_Access can be defined as
subtype String_Access is String'Access;
*************************************************************
From: Randy Brukardt
Sent: Tuesday, May 09, 2000 6:31 PM
To: 'Ada-Comment List'
> In the light of the fact that when strings are handled, very often (I would
> even say, virtually always) an access type is also needed even if package
> Ada.Strings.Unbounded is not used, I would propose to shift these declarations
> to the place where type String is defined, 3.6.3. [And correspondingly for
> wide strings A.4.7.]
This would be a very bad idea. Introducing names in Standard is *very*
incompatible with existing code, as the names in Standard cannot be hidden, and
would override any names currently accessible by a use clause.
For instance, if a program contained:
package P is
type String_Access is access all My_String;
end P;
procedure M is
use P;
V : String_Access;
...
Your proposal would change V's type (silently!) from P.String_Access to
Standard.String_Access. One place that would happen is for the declarations in
Ada.Strings.Unbounded that started the discussion!
Besides, your second proposal is a better way to accomplish the same thing
without polluting Standard.
> In a step further, I would propose a new 'Access attribute for types:
> Given any type T, T'Access would denote the following
> predefined general access type
>
> type T'Access is access all T;
This proposal looks rather attractive, but would be quite expensive on compilers
hosted on memory-limited hosts. (Perhaps that doesn't matter anymore??)
In any case, this exact proposal was made by Bob Duff in response to another
proposal. I will attach your comment to that AI (AI-00230), because I don't want
to spend anyone's time on the first proposal.
*************************************************************
From: Robert A Duff
Sent: Wednesday, May 10, 2000 10:14 AM
> > type T'Access is access all T;
> This proposal looks rather attractive, but would be quite expensive on
> compilers hosted on memory-limited hosts. (Perhaps that doesn't matter
> anymore??)
I'm not sure why it is expensive. But I do think nobody should be
running compilers on anything less than a 32-bit address space.
(Target machines are often smaller, though.)
> In any case, this exact proposal was made by Bob Duff in response to another
> proposal.
Actually, I think it was Robert Dewar's idea;
I supported it.
*************************************************************
From: Robert Dewar
Sent: Tuesday, May 09, 2000 7:46 PM
I strongly agree that introducing names into standard is a bad idea.
As for type'Access, let's give credit where credit is due, I pushed this
idea strongly during the design process, but it was rejected. note that
the proposal in its current form is in any case incompatible with the
current language design, which ascribes a quite different meaning top
to type'Access in certain contexts.
The objection to my proposal at the time was strong and clearly the majority
viewpoint. The basis of this objection was that providing this distinguished
anonymous type would tend to decrease type safety by encouraging the use of
this type instead of properly typed access types. I see nothing that would
change people's minds, and I think there is considerable merit in the majority
viewpoint, so I see no argument for reopening this issue.
By the way, the idea of putting this unreferenced type where it is was
precisely to provide a standard string access type, does anyone use it
this way?
*************************************************************
From: Randy Brukardt
Sent: Wednesday, May 10, 2000 11:44 AM
> By the way, the idea of putting this unreferenced type where it is was
> precisely to provide a standard string access type, does anyone use it
> this way?
I didn't even realize this type was in Ada.Strings.Unbounded until this
comment, so for me at least, the answer is no.
*************************************************************
From: Robert A Duff
Sent: Wednesday, May 10, 2000 3:26 PM
> I strongly agree that introducing names into standard is a bad idea.
As Tuck is fond of pointing out, it's almost the same thing as adding a
new reserved word to the language.
> As for type'Access, let's give credit where credit is due, I pushed this
> idea strongly during the design process, but it was rejected.
Right.
>... note that
> the proposal in its current form is in any case incompatible with the
> current language design, which ascribes a quite different meaning top
> to type'Access in certain contexts.
Heh? What's type'Access?
> The objection to my proposal at the time was strong and clearly the majority
> viewpoint. The basis of this objection was that providing this distinguished
> anonymous type would tend to decrease type safety by encouraging the use of
> this type instead of properly typed access types. I see nothing that would
> change people's minds, and I think there is considerable merit in the majority
> viewpoint, so I see no argument for reopening this issue.
I see no merit whatsoever in the majority viewpoint. Most programs I've
seen (or written) declare exactly one access type per designated type,
right after the designated type is declared. So in practise, people are
*not* taking advantage of strongly typed access types. Contrast this
with (for example) integer types, where most programmers define a new
integer type for each distinct purpose in the program.
I think there *is* new information on the subject: people have realized
from experience with Ada 95 that it's a big pain to have type
conversions all over the place for perfectly safe cases (eg,
access-to-T2'Class converted to access-to-T1'Class, where T2 is derived
from T1, so conversions from T2'Class to T1'Class are of course
implicit). These bogus type conversions damage readability. And part
of the solution that has been discussed involves the T'Access idea.
> By the way, the idea of putting this unreferenced type where it is was
> precisely to provide a standard string access type, does anyone use it
> this way?
I doubt it. Lots of programs don't use unbounded strings, so it
wouldn't occur to the programmer to use this type. But it's harmless,
so no change is needed. We're certainly not going to delete the type,
and we're certainly not going to add a new type to package Standard.
*************************************************************
From: Gary Dismukes [dismukes@gnat.com]
Sent: Wednesday, May 10, 2000 5:08 PM
> >... note that
> > the proposal in its current form is in any case incompatible with the
> > current language design, which ascribes a quite different meaning top
> > to type'Access in certain contexts.
>
> Heh? What's type'Access?
I'm guessing that Robert's referring to the case where the prefix
is a current instance name (looks like a type name, though technically
it's the name of an object of course).
*************************************************************
From: Robert Dewar
Sent: Wednesday, May 10, 2000 7:48 PM
Yup! That's what I was referring to, that is indeed the only context
in which type'access can appear in the current language.
*************************************************************
From: Robert A Duff
Sent: Thursday, May 11, 2000 9:46 AM
> > Heh? What's type'Access?
>
> I'm guessing that Robert's referring to the case where the prefix
> is a current instance name (looks like a type name, though technically
> it's the name of an object of course).
Isn't it *always* the name of the instance? I mean, even if we chose to
call it T'Pointer, we would have a problem, because the attribute would
be unusable inside the type. Not a big problem, but it would be
annoying, because access types are quite often used to make
self-referential record types.
*************************************************************
From: Robert Dewar [dewar@gnat.com]
Sent: Thursday, May 11, 2000 3:47 AM
To: ada-comment@ada-auth.org
Subject: Re: [Ada-Comment] Predefined Access Types
<<Where is T'Access defined? Oh - within record type definitions where it
stands for the current instance of the type.>>
Much more significantly, within tasks and protected objects to denote
the current concurrent object.
*************************************************************
From: Gary Dismukes
Sent: Thursday, May 11, 2000 1:34 PM
> Isn't it *always* the name of the instance? I mean, even if we chose to
> call it T'Pointer, we would have a problem, because the attribute would
> be unusable inside the type. Not a big problem, but it would be
> annoying, because access types are quite often used to make
> self-referential record types.
Yes, that's right, it will always denote the instance within the
type, though I suppose that if a new attribute such as 'Pointer
or whatever were used it could be defined to apply to the type
of the object in the case of an object prefix, hmm.
Anywya, as you say, the restriction within a type is annoying but
doesn't seem like a major problem. You could still use a workaround
such as applying 'Access to a subtype name.
*************************************************************
From: Robert Dewar
Sent: Wednesday, May 10, 2000 7:52 PM
<<Actually, I think it was Robert Dewar's idea;
I supported it.>>
Ah Bob, if you supported it, then you can't move for a reconsideration.
To convince ourselves it is worth refighting this, we have to have at
least one person change their minds :-)
*************************************************************
From: Christoph Grein
Sent: Thursday, May 11, 2000 12:00 AM
> I strongly agree that introducing names into standard is a bad idea.
OK, I see the point.
> .... note that
> the proposal in its current form is in any case incompatible with the
> current language design, which ascribes a quite different meaning top
> to type'Access in certain contexts.
RM K(2): P'Access where P denotes a subprogram
RM K(4): X'Access where X denotes an object
Where is T'Access defined? Oh - within record type definitions where it
stands for the current instance of the type.
> By the way, the idea of putting this unreferenced type where it is was
> precisely to provide a standard string access type, does anyone use it
> this way?
>
No, I dislike the idea of withing Strings.Unbounded just for this type
when I do not use any other operations of the package. So the type is
really misplaced.
The proper place in light of all the arguments presented seems to be
package Strings (RM A.4.1).
*************************************************************
From: Robert A Duff
Sent: Thursday, May 11, 2000 7:28 AM
> The proper place in light of all the arguments presented seems to be
> package Strings (RM A.4.1).
Package Strings has pragma Pure, which disallows access types.
Come to think of it, Standard has pragma Pure, too, which is *another*
reason we can't put type String_Access in Standard.
By the way, I wish there were a way to declare access types without
allocators; then we could allow *those* kinds of access types in
pragma-pure packages.
I agree with you that String_Access is in a weird place.
But it's harmless. If you don't want to use it,
you can easily declare your own. Not ideal, but it works.
*************************************************************
From: Michael Yoder
Sent: Thursday, May 11, 2000 10:11 AM
Christopher Grein wrote:
>
>The proper place in light of all the arguments presented seems to be
>package Strings (RM A.4.1).
>
Doing this would require (under current rules) changing package Strings
from pure to preelaborated. This potentially breaks existing code; it
seems unlikely that a user would write an existing pure package that
depends on Strings, but it's certainly imaginable (e.g., by renaming the
exceptions).
Earlier someone asked if anyone ever used the access type in
Strings.Unbounded. I have, two or three times. In each case, I knew other
parts of the program were using unbounded strings, so there was no cost to
doing so. I believe however that I would do it in any case, since IMO most
large programs use unbounded strings at least once, and a small program
won't be made a large one just by including one extra package. Even so, I
agree the type doesn't belong where it's put, and I have encountered at
least one space-constrained program for which this consideration mattered.
Perhaps a least bad solution would be to put the type in its own small
child of Strings, and make the type in Strings.Unbounded be a "renaming as
subtype" of that type. This would (I think) be entirely compatible with
the existing state of affairs.
*************************************************************
From: Christoph Grein
Sent: Friday, May 12, 2000 12:01 AM
> Doing this would require (under current rules) changing package Strings
> from pure to preelaborated. ...
OK, I again see the point.
> Perhaps a least bad solution would be to put the type in its own small
> child of Strings, and make the type in Strings.Unbounded be a "renaming as
> subtype" of that type. This would (I think) be entirely compatible with
> the existing state of affairs.
Hey, I think that's a brilliant idea.
An access to String is so often needed that it should be predefined in the
language, and Michael's proposal just does this in an innocuous way.
package Ada.Strings.Yoder is
pragma Preelaborate(Yoder);
type String_Access is access all String;
procedure Free (X : in out String_Access);
end Ada.Strings.Yoder;
*************************************************************
From: Robert Dewar
Sent: Friday, May 12, 2000 12:59 AM
You can even imagine a special implementation of Ada.Strings;Yoder that
would use some special storage pool to handle string accesses
especially efficiently???
*************************************************************
From: Michael Yoder
Sent: Friday, May 12, 2000 2:30 PM
This is a good idea in any case (that is, it can be done for the type in
Strings.Unbounded even if Strings.Yoder never becomes part of Ada0X :-).
*************************************************************
From: Robert A Duff
Sent: Thursday, May 11, 2000 8:21 PM
> Bob, were you for or against type'Access the first time around?
> I can't remember :-)
Sometimes I can't remember what I was for or against in the past ;-),
but in this case I've been for it, or something like it, all along.
...
> Ah Bob, if you supported it, then you can't move for a reconsideration.
> To convince ourselves it is worth refighting this, we have to have at
> least one person change their minds :-)
OK.
But it *was* brought up again, independently, as part of the solution to
some other AI. I can't remember which. (*Editor's note: This one!*)
*************************************************************
From: Robert Dewar
Sent: Friday, May 12, 2000 12:57 AM
Well I sure would like to see something like typ'Access come back if it
can be figured out how to do it cleanly.
*************************************************************
From: Christoph Grein
Sent: Friday, May 12, 2000 12:14 AM
> <<Where is T'Access defined? Oh - within record type definitions where it
> stands for the current instance of the type.
> >>
>
> Much more significantly, within tasks and protected objects to denote
> the current concurrent object.
>
Thank you, Robert, for the details.
Wouldn't it be a good idea to include T'Access with such a hint in Annex K?
This annex is "informative", so IMO a good place for a statement like this.
*************************************************************
From: Robert Dewar
Sent: Friday, May 12, 2000 1:05 AM
<<Wouldn't it be a good idea to include T'Access with such a hint in Annex K?
This annex is "informative", so IMO a good place for a statement like this.
>>
Well this already is in Annex K:
4 X'Access
For a prefix X that denotes an aliased view of an object:
THe case of subtype_name'Access is just a special case where subtype_name
is defined to denote a specific aliased view, namely the current instance.
It would be confusing to have an entry saying
T'Access For a prefix that denotes a subtype T,
... since in this case T does not denote a subtype.
I suppose one could argue for a note, but my feeling is that notes belong
in text books, not in the RM. Also notes in informative annexes are a bit
odd I would think.
Although this is a summary and is informative, it is definitely written
in the style of normative text, so a note still needs to be labeled a
note I would think.
*************************************************************
From: Robert A Duff
Sent: Friday, May 12, 2000 1:14 PM
> I suppose one could argue for a note, but my feeling is that notes belong
> in text books, not in the RM. Also notes in informative annexes are a bit
> odd I would think.
I guess they would be doubly informative. ;-)
> Although this is a summary and is informative, it is definitely written
> in the style of normative text, ...
In fact, this text is identical to the normative text in the body of the
RM that describes these attributes. So it's not surprising that it's in
the same style. ;-)
In the source code for the RM (in Scribe), the attributes are written as
macro calls, which generate the inline text, and also send the same text
to a separate file, which gets sorted by attribute name, and then
re-included back into Annex K.
The pragmas have a similar mechanism.
I think to build the Postscript version of the RM, you had to run Scribe
three times in a row, because the output of one run would get sucked up
into the next run as input, and it had to "settle down". Sort of like
bootstrapping a compiler.
Randy is in the process of modernizing this software. ;-)
>... so a note still needs to be labeled a
> note I would think.
I tend to think it's not the job of ARG to teach people Ada. As Robert
says, there are textbooks.
*************************************************************
From: Robert A Duff
Sent: Friday, May 12, 2000 4:04 PM
Mike and Robert,
> Robert Dewar wrote:
> >You can even imagine a special implementation of Ada.Strings;Yoder that
> >would use some special storage pool to handle string accesses
> >especially efficiently???
>
> This is a good idea in any case (that is, it can be done for the type in
> Strings.Unbounded even if Strings.Yoder never becomes part of Ada0X :-).
I guess you're going to be famous, Mike. Nobody else has a predefined
Ada package named after them. Hey, maybe the ARG could make money by
letting large corporations put their names on things. Package Calendar
could be renamed package FleetBank, and so on.
Anyway, I'm not sure what you guys are getting at with efficient storage
pools. What's special about String_Access? The fact that the
designated type is an unconstrained array? Surely not the fact that
it's predefined. What sort of special pool are you talking about, and
whatever it is, why wouldn't it be a good idea for *any* "type Mumble is
access all Unconstrained_Array;" that appears anywhere in any program?
*************************************************************
From: Robert A Duff
Sent: Friday, May 12, 2000 4:38 PM
I wrote:
> I guess you're going to be famous, Mike. Nobody else has a predefined
> Ada package named after them.
Except for Ada herself, of course!
*************************************************************
From: Michael Yoder
Sent: Monday, May 15, 2000 9:25 AM
Bob Duff wrote:
>Anyway, I'm not sure what you guys are getting at with efficient storage
>pools. What's special about String_Access? The fact that the
>designated type is an unconstrained array? Surely not the fact that
>it's predefined. What sort of special pool are you talking about, and
>whatever it is, why wouldn't it be a good idea for *any* "type Mumble is
>access all Unconstrained_Array;" that appears anywhere in any program?
String_Access is special because you can probably improve performance by
making assumptions about the frequency of allocation of various lengths. A
simpler possibility is to choose the algorithm so as to specifically
support Strings.Unbounded : this can be done by usiing a binary-buddy
allocator when the length is a power of 2, for example. (I haven't
actually tried any such scheme, so I suppose I should qualify my enthusiasm
by saying that the idea is potentially good rather than good. But the idea
of exploring such schemes is good. :-)
If Ada had a predefined generic for vectors of variable length, it could
probably use the same allocator as that for Strings.Unbounded.
If the above is still overly concise, I'm willing to elaborate further.
*************************************************************
From: Michael Yoder
Sent: Monday, May 15, 2000 11:36 AM
Robert Duff wrote:
>I guess you're going to be famous, Mike. Nobody else has a predefined
>Ada package named after them. Hey, maybe the ARG could make money by
>letting large corporations put their names on things. Package Calendar
>could be renamed package FleetBank, and so on.
I would hate to have to buy dark glasses in order to travel incognito. :-)
So, let me propose Ada.Strings.Accesses as a name for this supposed package.
>Anyway, I'm not sure what you guys are getting at with efficient storage
>pools.
I should perhaps state that my experience makes me at least as inclined to
worry about fragmentation behavior as efficiency. In either case, there is
potential benefit in treating strings specially.
*************************************************************
From: Robert Dewar
Sent: Monday, October 1, 2001 5:57 AM
I think that all AI's that propose new features should have a section
discussing the need for any work in the area. I am afraid we are going
into the mode of language experts writing up things that would be nice
to have, if we are not careful.
*************************************************************
From: Tucker Taft
Sent: Monday, October 1, 2001 10:44 AM
I believe that is at least part of the intent of the "!problem"
section. Apparently the "problem" section of this AI was inadequate.
Also, in this case, we discussed the need quite a bit at the last
ARG meeting, so I was more focused on writing up the technical
aspects of the proposal, than justifying its need. I do agree with
the important of having a good justification.
*************************************************************
From: Robert Dewar
Sent: Monday, October 1, 2001 11:00 AM
The important thing here is that the justification include some evidence
that this is a real world issue, i.e. a purely technical nice-to-have
justification is dubious. We need some real world examples or input.
*************************************************************
From: Randy Brukardt
Sent: Monday, October 1, 2001 8:05 PM
Robert said:
> I think that all AI's that propose new features should have a section
> discussing the need for any work in the area. I am afraid we are going
> into the mode of language experts writing up things that would be nice
> to have, if we are not careful.
As Tucker responded, this is the propose of the !problem section. If the
!problem of an AI isn't convincing, then the AI has a (ahem) problem, no matter
what the merits of the proposal.
> The important thing here is that the justification include some evidence
> that this is a real world issue, i.e. a purely technical nice-to-have
> justification is dubious. We need some real world examples or input.
My own guess is that is going to be hard to come by on this one. This proposal
grew out an attempt to save "with type"; now that that has been scuttled, the
need for this one is much less compelling.
At least, this proposal gets rid of the run-time accessibility for every object
that we had discussed at the last meeting. But I'm still concerned that static
accessibility might not be enough to implement this (especially in shared
generics, where the static level /= instantiation level).
If I ever get some spare time, I'll have to think about this one some more.
*************************************************************
From: Robert Dewar
Sent: Monday, October 1, 2001 8:27 PM
<<My own guess is that is going to be hard to come by on this one. This
proposal grew out an attempt to save "with type"; now that that has been
scuttled, the need for this one is much less compelling.>>
The important thing to realize about proposals for additions is that the
dynamics have in my view shifted completely. In the old days, the ARG
could via WG9 and ACATS essentially command all implementors to implement
feature X and they had to jump.
Now, at least speaking for ACT, but I suspect for other vendors too, the
issue of whether new features get implemented is far more dependent on
what real customers want. If a new feature is approved, or even "mandated"
it will not get implemented unless customers need/want it implemented and
resources are consequently available.
That's why it is so important to make sure that real demand exists before
we sit around designing neat features that would be nice to have.
*************************************************************
From: Tucker Taft
Sent: Monday, October 1, 2001 11:29 PM
Randy Brukardt wrote:
> ...
> > The important thing here is that the justification include some evidence
> > that this is a real world issue, i.e. a purely technical nice-to-have
> > justification is dubious. We need some real world examples or input.
>
> My own guess is that is going to be hard to come by on this one. This
> proposal grew out an attempt to save "with type"; now that that has been
> scuttled, the need for this one is much less compelling.
I don't see that as the primary justification. The major
need relates to the large number of unnecessary explicit
conversions when using Ada 95 for "normal" OO-style
programming. The connection with "with type" was pretty
remote, in my view.
>
> At least, this proposal gets rid of the run-time accessibility for every
> object that we had discussed at the last meeting. But I'm still concerned
> that static accessibility might not be enough to implement this (especially
> in shared generics, where the static level /= instantiation level).
>
> If I ever get some spare time, I'll have to think about this one some more.
In thinking about this more, I have concluded that we should allow
access_definitions in component subtype indications, but with the
same rules as for discriminants, namely that the accessibility level
of the anon subtype is the same as the level of the enclosing composite
object. This jibes with the fact that typically a set of objects that
point at each other all have the same lifetime.
I didn't adequately deal with allocators. I think if an allocator appears
as the expression of a return statement, where the return type is specified
using an access_definition, then the storage pool to use for the allocator
is determined by the caller. This creates a very useful capability for
a function to do an allocation in a storage pool determined by context.
This is a fundamental requirement for region-based memory allocation,
which is becoming recognized as the "thinking person's alternative" to
full garbage collection. This argues for a uniform treatment of
such functions, namely that they are implicitly passed both the "caller"
accessibility level and the target storage pool for allocators.
*************************************************************
From: Robert Dewar
Sent: Tuesday, October 2, 2001 5:22 AM
<<I don't see that as the primary justification. The major
need relates to the large number of unnecessary explicit
conversions when using Ada 95 for "normal" OO-style
programming. The connection with "with type" was pretty
remote, in my view.
>>
That's one level remote to me, I need a "major need" to be expressed
in terms of actual people writing actual code with actual needs and
examples.
I am afraid that the ARG is trying to take on the job of requirements
gathering for language enhancements without sufficient connection to
the outside world. We haven't even asked *vendors* what they think is
important, let alone asking actual Ada users. Language designers are
not the right people to be deciding on what is really important to
add.
For example, if you were to ask ACT what the single most important
feature needed was, I suspect it would be C++ interfacing features.
I certainly can't remember any customer asking about "large number
of unnecessary explicit conversions" :-)
*************************************************************
From: Randy Brukardt
Sent: Tuesday, October 2, 2001 1:18 PM
> I am afraid that the ARG is trying to take on the job of requirements
> gathering for language enhancements without sufficient connection to
> the outside world. We haven't even asked *vendors* what they think is
> important, let alone asking actual Ada users.
Many vendors participate in this group, and have rarely been shy about
expressing their views. Certainly, ACT has been happy to provide this at every
opportunity. :-)
But I would caution against using requests to vendors as the only criteria. The
Ada community has a strong commitment to following standards, and thus I would
not expect most customers to ask their vendor to "break" the standard.
Therefore, I'd expect enhancement requests to vendors to involve areas outside
of the standard (interfacing to other languages, additional provided packages,
performance issues, etc.), and most of that isn't interesting to the ARG any.
To take a specific example. When we were building Claw, we wasted a lot of time
tracking down "bugs" caused by broken overridding (where we thought some
routine was overridding, but wasn't due to a spelling error or missing
parameter). We didn't run to a vendor (even though I probably could have
convinced one to do something :-) to fix this: we just put it down to bad
language design and lived with it. The only thing we did is mention it toward
the end of our paper on Claw. Only when I wrote up an amendment AI on the topic
(mainly to provide a fully fleshed out example AI to get comments on the format
of an amendment) did I find out that many other people shared this frustration.
I doubt anyone ran to ACT to ask for an enhancement here (although they might
now that there is a fully defined solution).
> Language designers are not the right people to be deciding on what is
> really important to add.
This is true, but I would argue that the majority of the ARG membership aren't
"language designers" per se, but vendors and/or users of Ada. Of course,
everyone is a "language designer" from time-to-time.
> I need a "major need" to be expressed
> in terms of actual people writing actual code with actual needs and
> examples.
For this particular AI, I certainly agree. So far as I remember, the problem
was driven by complaints from Erhard's students. While these are "actual
people", I have my doubts that they meet the "actual needs" qualification.
Moreover, we built Claw (certainly a large O-O system) without running into
this problem. I would much rather have "in out" parameters on functions (as
that would fix a real problem that we have had with O-O programs) than this
proposal [access parameters are not a real replacement for "in out" parameters,
as the calls are much more complex].
*************************************************************
From: Robert Dewar
Sent: Tuesday, October 2, 2001 1:44 PM
<<Many vendors participate in this group, and have rarely been shy about
expressing their views. Certainly, ACT has been happy to provide this at
every opportunity. :-)>>
There is a different between having some technical person participating
in the ARG meetings, and getting formal input from vendors.
<<But I would caution against using requests to vendors as the only criteria.
The Ada community has a strong commitment to following standards, and thus I
would not expect most customers to ask their vendor to "break" the standard.
Therefore, I'd expect enhancement requests to vendors to involve areas
outside of the standard (interfacing to other languages, additional provided
packages, performance issues, etc.), and most of that isn't interesting to
the ARG any.>>
The ARG should be more interested in such issues. yes, I know it is more
fun for language designers to design neat new features -- and that's my
point.
Surely we should not use requests to vendors as the only criterion, but
it's a better sole criterion than using the input from language designers
as the only criterion.
In fact we get a wide variety of requests from customers, after all,
WITH TYPE is there because customers needed it, not because there was
some AI suggesting it, as an example.
<<Only when I wrote up an amendment AI on the topic (mainly to provide a fully
fleshed out example AI to get comments on the format of an amendment) did I
find out that many other people shared this frustration. I doubt anyone ran
to ACT to ask for an enhancement here (although they might now that there is
a fully defined solution).
>>
Remember that in our environment, customers ask us if they have any
questions or problems whatsoever in using Ada. All the time, they
are asking us "how do we do this in Ada", or "can't we find a better
way of doing things than this". So indeed we have lots of input of
this kind, but I can't find many things that would be worth new language
features.
Right now, I think there is a real danger of designing language features
that no one will implement, and thus making an updated standard irrelevant.
<<For this particular AI, I certainly agree. So far as I remember, the problem
was driven by complaints from Erhard's students. While these are "actual
people", I have my doubts that they meet the "actual needs" qualification.
Moreover, we built Claw (certainly a large O-O system) without running into
this problem. I would much rather have "in out" parameters on functions (as
that would fix a real problem that we have had with O-O programs) than
proposal [access parameters are not a real replacement for "in out"
parameters, as the calls are much more complex].
>>
The lack of in out parameters in functions, a restriction that as far as
I can tell is, like the peculiar declaration ordering rules in 83, there
only because someone thinks it is more consistent with some particular
coding philosophy (*), is indeed a significant problem.
Robert Dewar
(*) I continue to find it odd that the design principle for functions in
the Ada language is "functions can have arbitrary side effects, but no
hint of this is allowed in the function specification. If you want to
make a state change in a function, it cannot be done using IN OUT
parameters in the spec, instead it must be done covertly using global
variables" :-)
*************************************************************
From: Dan Eilers
Sent: Tuesday, October 2, 2001 2:13 PM
Robert Dewar wrote:
> (*) I continue to find it odd that the design principle for functions in
> the Ada language is "functions can have arbitrary side effects, but no
> hint of this is allowed in the function specification. If you want to
> make a state change in a function, it cannot be done using IN OUT
> parameters in the spec, instead it must be done covertly using global
> variables" :-)
Well, to some extent, declaring a global variable is an overt invitation
for modification by any code within its scope. The covertness problem
with IN OUT parameters on functions is that there is no indication at
the point of the call that parameters might be modified, where such
parameters are likely to be local variables with no signal to the
reader that they are modified by the function call. I believe this
problem was pointed out in C.A.R. Hoare's famous 1973 paper "Hints
on Programming Language Design".
*************************************************************
From: Randy Brukardt
Sent: Tuesday, October 2, 2001 3:08 PM
Which of course applies equally to procedure calls. And I have been
occassionally surprised by procedures modifying parameters, and it would be
nice if that was identified in the call. But it seems about 20 years too late
to complain about that...
*************************************************************
From: Robert Dewar
Sent: Tuesday, October 2, 2001 10:39 PM
Fine, people who have this point of view can restrict their use of the
language. No one suggests removing USE clauses just because some
people think they are a bad idea.
*************************************************************
From: Dave Emery
Sent: Tuesday, October 2, 2001 2:10 PM
At 14:44 -0400 10/2/01, dewar@GNAT.COM wrote:
>...
>The lack of in out parameters in functions, a restriction that as far as
>I can tell is, like the peculiar declaration ordering rules in 83, there
>only because someone thinks it is more consistent with some particular
>coding philosophy (*), is indeed a significant problem.
Can I vote for reconsidering/removing this (stupid) restriction?
If one argument in favor of keeping it is to allow the compiler
or some third-party verification tool to assume or to check
that the function has no side-effects, I'd rather do that
check with a pragma, and allow/trust the user to do the
right thing at the right time. Certainly this has been
a very painful restriction for interfacing with other languages
that do not accept this point of dogma :-)
*************************************************************
From: Randy Brukardt
Sent: Tuesday, October 2, 2001 3:03 PM
> The ARG should be more interested in such issues. yes, I know it is more
> fun for language designers to design neat new features -- and that's my
> point.
I understand, but in practice, there haven't been much in the way of expanding
the language. When I proposed the Ada.Directories package, there was a lot of
opposition of "not important enough" (and you originally led the charge on
that). As far as C++ interfacing goes, we discussed this at the Westboro
meeting (September 1999), but no one had any proposals on what to do. The
existing work was all rather implementation-dependent. (Ed was at that meeting,
and presented various GNAT features to the group, but I don't recall if he was
there for this discussion.) And so far as I know, nothing has been proposed
since.
> Remember that in our environment, customers ask us if they have any
> questions or problems whatsoever in using Ada. All the time, they
> are asking us "how do we do this in Ada", or "can't we find a better
> way of doing things than this". So indeed we have lots of input of
> this kind, but I can't find many things that would be worth
> new language features.
I also get questions of the sort of "how do you do X?", but I'm never thinking
about new language features when I answer them. "Wait until 2006" doesn't seem
likely to satisfy many customers!
> Right now, I think there is a real danger of designing language features
> that no one will implement, and thus making an updated standard irrelevant.
Understandable, and AI-230 is certainly a possible offender in this area.
> The lack of in out parameters in functions, a restriction that as far as
> I can tell is, like the peculiar declaration ordering rules in 83, there
> only because someone thinks it is more consistent with some particular
> coding philosophy (*), is indeed a significant problem.
I've always figured that I should have the power to re-open this issue, as I
was one of the people who fought tooth-and-nail to keep it in Ada 95. The main
reason is that the Janus/Ada intermediate code does not allow copy-back for
function calls -- and changing this would be a very large change to the
optimizer and code generator. (Function calls always discard their parameters.)
My mind was changed by our work on Claw. The first problem was a query
function:
function Is_Something (Window : in Root_Window_Type) return Boolean is
begin
-- Long calculation involving several system calls.
return Answer;
end Is_Something;
Is_Something (I forget the exact function involved) was likely to be called
frequently, so I wanted to save the result I calculated in the Window object.
So I added a component to save the value and a component to say whether the
first component was, and got a compile-time error trying to set them. Ugh.
The problem has occurred repeatedly during the development of Claw. Some
operations that we would have preferred to be functions ended up as procedures
since we needed to modify the object. On a few occasions, we used the fact that
Claw objects are assignable, and "clones" of each other to work around the
problem:
function Is_Something (Window : in Root_Window_Type) return Boolean is
Writable_Copy : Root_Window_Type'Class := Window;
begin
-- Modify components of Writable_Copy, which modifies the original object.
return Answer;
end Is_Something;
But that is horrible (and inefficient).
I've tried to raise the "in out" issue at the ARG meetings without success.
People are afraid that the same old bunch of opponents (minus at least one --
me!) would resurface.
*************************************************************
From: Tucker Taft
Sent: Friday, February 1, 2002 11:54 AM
Here is an update to ai-00230 on anonymous access types.
I was able to resolve the problems that I had with them last time,
while eliminating the mind-bending named subtypes of anonymous access types,
but adding back components of an anonymous access type.
I think it all works safely and usefully now, especially presuming
the syntax for "access_definition" is generalized (see ai-231) to allow
control over nullness, and constantness of the designated object.
[See AI body for current proposal - Ed.]
*************************************************************
Editor's notes, October 22, 2003
In creating !corrigendum sections for this AI, I noticed that several wording
changes are needed only if AI-231 is approved. I moved these wording changes
to that AI. AI-231 should be written to presume that AI-230 is approved (as it
is ahead of AI-231 in the ARG process); in particular, the needed change to
8.5.1(4) should be included in AI-231.
*************************************************************
From: Javier Miranda
Sent: Tuesday, January 27, 2004 10:50 AM
Following paragraph was removed from version 1.13 to version 1.14:
-Change 3.4.1(3) as follows:
-
- Every type is either a specific type, a class-wide type, or a universal
- type. A specific type is one defined by a type_declaration, a
- formal_type_declaration, an access_definition, or a full type definition
- embedded in a declaration for an object. Class-wide and universal types are
- implicitly defined, to act as representatives for an entire class of types,
- as follows:
As a consequence, following paragraph (in the !discussion section)
should also be removed:
"We also fix an RM bug here; 3.4.1(3) says that all types are either specific,
class-wide, or universal, but then fails to include access_definition (for
anonymous access types) in any of those categories."
*************************************************************
From: Bob Duff
Sent: Monday, June 6, 2005 12:38 PM
I'm using draft 11.8 of the [A]ARM.
6.1(15/2):
15/2 {AI95-00231-01} parameter_specification ::=
defining_identifier_list : mode [null_exclusion] subtype_mark
[:= default_expression]
| defining_identifier_list : access_definition
[:= default_expression]
Why do we disallow access parameters of modes 'in out' or 'out'?
We've gone to all this trouble to allow anonymous access types everywhere, but
here's a case where programmer's will have to declare a named access type.
Are there any other cases where the name of an access type is allowed, but an
access definition is not?
*************************************************************
From: Tucker Taft
Sent: Monday, June 6, 2005 7:27 PM
Groan. I think there could be some significant
implementation issues and possible dangling-reference
possibilities with writable access parameters,
since their accessibility level is dynamic.
I also find the idea of "out access constant D"
pretty painful to imagine, bordering on the
C++ "const" nightmare. I think we would be
asking for trouble to introduce these at this
late date.
*************************************************************
From: Randy Brukardt
Sent: Monday, June 6, 2005 9:59 PM
> Why do we disallow access parameters of modes 'in out' or 'out'?
I don't know, ask the Ada 9X team. :-) They were requested several times, I
believe.
> We've gone to all this trouble to allow anonymous access types everywhere, but
> here's a case where programmer's will have to declare a named access type.
As Tucker points out, they would be a real mess to allow, mainly because of
accessibility. Of course, the only reason we need these special properties
are because some people wouldn't allow "in out" parameters (at least for
tagged types) in functions. But that will never be fixed, and thus we're
stuck with this abomination.
> Are there any other cases where the name of an access type is allowed, but an
> access definition is not?
A type conversion or qualification, of course. And I can hardly imagine
trying to fix that! Imagine:
List := not null access constant T(Func(A, B));
John's work on the Rationale shows that you need named types in various
cases not having to do with parameter passing, in part because the implicit
conversions are only allowed when the checks cannot fail. And there are
enough cases where the checks *could* fail that I think most stuff will end
up using named types anyway.
*************************************************************
From: Pascal Leroy
Sent: Tuesday, June 7, 2005 3:34 AM
> Why do we disallow access parameters of modes 'in out' or
> 'out'?
Arrrgh! Don't even think of it at this late stage.
*************************************************************
From: Gary Dismukes
Sent: Tuesday, June 7, 2005 12:37 PM
> John's work on the Rationale shows that you need named types in various
> cases not having to do with parameter passing, in part because the implicit
> conversions are only allowed when the checks cannot fail. And there are
> enough cases where the checks *could* fail that I think most stuff will end
> up using named types anyway.
This comment of Randy's caught my eye. Specifically, I'm wondering about
the part that says "implicit conversions are only allowed when the checks
cannot fail." What does that follow from? In the process of considering
accessibility checks needed for the new entities that can have an anonymous
access type I was looking at cases such as the following:
A : access Integer := ...;
procedure Proc (X : access Integer) is
begin
A := X;
end Proc;
If the above assignment is legal then it clearly requires a run-time check.
Is there a rule I'm missing that makes the assignment illegal?
*************************************************************
From: Randy Brukardt
Sent: Tuesday, June 7, 2005 1:49 PM
> This comment of Randy's caught my eye. Specifically, I'm wondering about
> the part that says "implicit conversions are only allowed when the checks
> cannot fail." What does that follow from?
That's the basic principle of implicit conversions, as explained by Tucker.
> In the process of considering accessibility checks needed for the new
> entities that can have an anonymous access type I was looking at cases
> such as the following:
>
> A : access Integer := ...;
>
> procedure Proc (X : access Integer) is
> begin
> A := X;
> end Proc;
>
> If the above assignment is legal then it clearly requires a run-time check.
> Is there a rule I'm missing that makes the assignment illegal?
I can't find one, which means either that the "basic principle" is garbage
(which makes me wonder why we don't allow tag checks in this case), or its
missing (which would make things less usable, of course). I don't see much
difference between tag checks and accessibility checks.
*************************************************************
From: Tucker Taft
Sent: Tuesday, June 7, 2005 3:30 PM
I think I must have been dreaming.
Imnplicit conversions are a result of the overload
resolution rules. They allow a particular "actual"
type to match a particular "expected" type.
The rules do not allow "downward" (narrowing)
implicit conversions. They say nothing
about accessibility.
4.6(17,20) (in the Ada *95* RM) disallow conversions
(implicit or explicit) when the static accessibility check
fails, but allow anonymous-to-anonymous
"implicit" conversion when a run-time check is required.
In fact, this already happens in Ada 95 in the following:
type T(access Integer) is limited null record;
type Acc_T is access T;
function New_T(X : access Integer) return Acc_T is
begin
return new T(X); -- accessibility check on implicit
-- acc type conversion
end New_T;
So I was obviously confused.
*************************************************************
Questions? Ask the ACAA Technical Agent