3.10 Access Types
1
{access type}
{access value}
{designate}
A value of an access type (an
access value)
provides indirect access to the object or subprogram it
designates.
Depending on its type, an access value can designate either subprograms,
objects created by allocators (see
4.8), or
more generally
aliased objects of an appropriate type.
{pointer:
See access value} {pointer
type: See access type}
1.a
Discussion: A name
denotes an entity; an access value designates an entity.
The “dereference” of an access value X, written “X.all”,
is a name that denotes the entity designated
by X.
Language Design Principles
1.b
Access values should always be well defined
(barring uses of certain unchecked features of Section 13). In particular,
uninitialized access variables should be prevented by compile-time rules.
Syntax
2/2
{
AI95-00231-01}
access_type_definition ::=
[null_exclusion] access_to_object_definition
|
[null_exclusion] access_to_subprogram_definition
3
access_to_object_definition ::=
access [
general_access_modifier]
subtype_indication
4
general_access_modifier ::= all |
constant
5
access_to_subprogram_definition ::=
access [
protected]
procedure parameter_profile
|
access [
protected]
function parameter_and_result_profile
5.1/2
6/2
{
AI95-00231-01}
{
AI95-00254-01}
{
AI95-00404-01}
access_definition ::=
[null_exclusion] access [constant] subtype_mark
| [null_exclusion] access [protected] procedure parameter_profile
| [null_exclusion] access [protected] function parameter_and_result_profile access subtype_mark
Static Semantics
7/1
{
8652/0012}
{
AI95-00062-01}
{access-to-object type} {access-to-subprogram
type} {pool-specific
access type} {general
access type} There are two kinds of access
types,
access-to-object types, whose values designate objects,
and
access-to-subprogram types, whose values designate subprograms.
{storage pool} Associated
with an access-to-object type is a
storage pool; several access
types may share the same storage pool.
All descendants
of an access type share the same storage pool. {pool
element} A storage pool is an area of
storage used to hold dynamically allocated objects (called
pool elements)
created by allocators[; storage pools are described further in
13.11,
“
Storage Management”].
8
{pool-specific access
type} {general
access type} Access-to-object types are
further subdivided into
pool-specific access types, whose values
can designate only the elements of their associated storage pool, and
general access types, whose values can designate the elements
of any storage pool, as well as aliased objects created by declarations
rather than allocators, and aliased subcomponents of other objects.
8.a
Implementation Note: The value of an
access type will typically be a machine address. However, a value of
a pool-specific access type can be represented as an offset (or index)
relative to its storage pool, since it can point only to the elements
of that pool.
9/2
{
AI95-00225-01}
{
AI95-00363-01}
{aliased} A
view of an object is defined to be
aliased if it is defined by
an
object_declaration or
component_definition
with the reserved word
aliased, or by a renaming of an aliased
view. In addition, the dereference of an access-to-object value denotes
an aliased view, as does a view conversion (see
4.6)
of an aliased view.
The Finally,
the current instance of a limited
tagged
type,
a protected type, a task type, or a type
that has the reserved word limited in its full definition is also
defined to be aliased. Finally, and
a formal parameter or generic formal object of a tagged type
is are
defined to be aliased. [Aliased views are the ones that can be designated
by an access value.]
{constrained
(object)} {unconstrained
(object)} {constrained
by its initial value} If the view defined
by an object_declaration is aliased, and the
type of the object has discriminants, then the object is constrained;
if its nominal subtype is unconstrained, then the object is constrained
by its initial value. [Similarly, if the object created by an allocator
has discriminants, the object is constrained, either by the designated
subtype, or by its initial value.]
9.a
Glossary entry: {Aliased} An aliased
view of an object is one that can be designated by an access value. Objects
allocated by allocators are aliased. Objects can also be explicitly declared
as aliased with the reserved word aliased. The Access attribute
can be used to create an access value designating an aliased object.
9.b
Ramification: The current instance of
a nonlimited type is not aliased.
9.c
The object created by an allocator is aliased,
but not its subcomponents, except of course for those that themselves
have aliased in their component_definition.
9.d
The renaming of an aliased object is aliased.
9.e
Slices are never aliased. See
4.1.2
for more discussion.
9.f/2
Reason: {
AI95-00225-01}
The current instance of a limited type is defined to be aliased so that
an access discriminant of a component can be initialized with T'Access
inside the definition of T.
Note that we don't
want this to apply to a type that could become nonlimited later within
its immediate scope, so we require the full definition to be limited.
9.g
A formal parameter of a tagged type is defined
to be aliased so that a (tagged) parameter X may be passed to an access
parameter P by using P => X'Access. Access parameters are most important
for tagged types because of dispatching-on-access-parameters (see
3.9.2).
By restricting this to formal parameters, we minimize problems associated
with allowing components that are not declared aliased to be pointed-to
from within the same record.
9.h
A view conversion
of an aliased view is aliased so that the type of an access parameter
can be changed without first converting to a named access type. For example:
9.i
type T1 is tagged ...;
procedure P(X : access T1);
9.j
type T2 is new T1 with ...;
procedure P(X : access T2) is
begin
P(T1(X.all)'Access); -- hand off to T1's P
. . . -- now do extra T2-specific processing
end P;
9.k/2
This paragraph
was deleted.{
AI95-00363-01}
The rule about objects with discriminants is necessary
because values of a constrained access subtype can designate an object
whose nominal subtype is unconstrained; without this rule, a check on
every use of such values would be required to ensure that the discriminants
of the object had not changed. With this rule (among others), we ensure
that if there might exist aliased views of a discriminated object, then
the object is necessarily constrained. Note that this rule is necessary
only for untagged types, since a discriminant of a tagged type can't
have a default, so all tagged discriminated objects are always constrained
anyway.
9.l/2
We considered making more kinds of objects aliased
by default. In particular, any object of a by-reference type will pretty
much have to be allocated at an addressable location, so it can be passed
by reference without using bit-field pointers. Therefore, one might wish
to allow the Access and and Unchecked_Access
attributes for such objects. However, private parts are transparent to
the definition of “by-reference type”, so if we made all
objects of a by-reference type aliased, we would be violating the privacy
of private parts. Instead, we would have to define a concept of “visibly
by-reference” and base the rule on that. This seemed to complicate
the rules more than it was worth, especially since there is no way to
declare an untagged limited private type to be by-reference, since the
full type might by nonlimited.
9.m
Discussion: Note that we do not use the
term “aliased” to refer to formal parameters that are referenced
through multiple access paths (see
6.2).
10
An
access_to_object_definition
defines an access-to-object type and its first subtype;
{designated
subtype (of a named access type)} {designated
type (of a named access type)} the
subtype_indication
defines the
designated subtype of the access type. If a
general_access_modifier
appears, then the access type is a general access type.
{access-to-constant
type} If the modifier is the reserved
word
constant, then the type is an
access-to-constant type[;
a designated object cannot be updated through a value of such a type].
{access-to-variable type}
If the modifier is the reserved word
all,
then the type is an
access-to-variable type[; a designated object
can be both read and updated through a value of such a type]. If no
general_access_modifier
appears in the
access_to_object_definition,
the access type is a pool-specific access-to-variable type.
10.a
To be honest: The type of the designated
subtype is called the designated type.
10.b
Reason: The modifier all was picked
to suggest that values of a general access type could point into “all”
storage pools, as well as to objects declared aliased, and that “all”
access (both read and update) to the designated object was provided.
We couldn't think of any use for pool-specific access-to-constant types,
so any access type defined with the modifier constant is considered
a general access type, and can point into any storage pool or at other
(appropriate) aliased objects.
10.c
Implementation Note: The predefined generic
Unchecked_Deallocation can be instantiated for any named access-to-variable
type. There is no (language-defined) support for deallocating objects
designated by a value of an access-to-constant type. Because of this,
an allocator for an access-to-constant type can allocate out of a storage
pool with no support for deallocation. Frequently, the allocation can
be done at link-time, if the size and initial value are known then.
10.d
Discussion: For the purpose of generic
formal type matching, the relevant subclasses of access types are access-to-subprogram
types, access-to-constant types, and (named) access-to-variable types,
with its subclass (named) general access-to-variable types. Pool-specific
access-to-variable types are not a separately matchable subclass of types,
since they don't have any “extra” operations relative to
all (named) access-to-variable types.
11
{access-to-subprogram
type} An
access_to_subprogram_definition
defines an access-to-subprogram type and its first subtype;
{designated
profile (of an access-to-subprogram type)} the
parameter_profile or
parameter_and_result_profile
defines the
designated profile of the access type.
{calling
convention (associated with a designated profile)} There
is a
calling convention associated with the designated profile[;
only subprograms with this calling convention can be designated by values
of the access type.] By default, the calling convention is “
protected”
if the reserved word
protected appears, and “Ada”
otherwise. [See
Annex B for how to override this
default.]
11.a
Ramification: The calling convention
protected is in italics to emphasize that it cannot be specified
explicitly by the user. This is a consequence of it being a reserved
word.
11.b/2
Implementation Note: {
AI95-00254-01}
For
a named an
access-to-subprogram type, the representation of an access value might
include implementation-defined information needed to support up-level
references — for example, a static link. The accessibility rules
(see
3.10.2) ensure that in a "global-display-based"
implementation model (as opposed to a static-link-based model),
a
named an access-to-(unprotected)-subprogram
value need consist only of the address of the subprogram. The global
display is guaranteed to be properly set up any time the designated subprogram
is called. Even in a static-link-based model, the only time a static
link is definitely required is for an access-to-subprogram type declared
in a scope nested at least two levels deep within subprogram or task
bodies, since values of such a type might designate subprograms nested
a smaller number of levels. For the normal case of
a
named an access-to-subprogram type
declared at the outermost (library) level, a code address by itself should
be sufficient to represent the access value in many implementations.
11.c
For access-to-protected-subprogram, the access
values will necessarily include both an address (or other identification)
of the code of the subprogram, as well as the address of the associated
protected object. This could be thought of as a static link, but it will
be needed even for global-display-based implementation models. It corresponds
to the value of the “implicit parameter” that is passed into
every call of a protected operation, to identify the current instance
of the protected type on which they are to operate.
11.d
Any Elaboration_Check is performed when a call
is made through an access value, rather than when the access value is
first "created" via a 'Access. For implementation models that
normally put that check at the call-site, an access value will have to
point to a separate entry point that does the check. Alternatively, the
access value could point to a "subprogram descriptor" that
consisted of two words (or perhaps more), the first being the address
of the code, the second being the elaboration bit. Or perhaps more efficiently,
just the address of the code, but using the trick that the descriptor
is initialized to point to a Raise-Program-Error routine initially, and
then set to point to the "real" code when the body is elaborated.
11.e
For implementations that share code between
generic instantiations, the extra level of indirection suggested above
to support Elaboration_Checks could also be used to provide a pointer
to the per-instance data area normally required when calling shared code.
The trick would be to put a pointer to the per-instance data area into
the subprogram descriptor, and then make sure that the address of the
subprogram descriptor is loaded into a "known" register whenever
an indirect call is performed. Once inside the shared code, the address
of the per-instance data area can be retrieved out of the subprogram
descriptor, by indexing off the "known" register.
11.f/2
This paragraph
was deleted.{
AI95-00344-01}
Essentially the same implementation issues arise
for calls on dispatching operations of tagged types, except that the
static link is always known "statically."
11.g/2
{
AI95-00254-01}
Note that access parameters of an anonymous access-to-subprogram type
are
not permitted.
Such If
there were such parameters
represent,
full “downward” closures
would be required,
meaning that in an implementation that uses a per-task (global) display,
the display
will would
have to be passed as a hidden parameter, and reconstructed at the point
of call.
This was felt to be an undue implementation
burden, given that an equivalent (actually, more general) capability
is available via formal subprogram parameters to a generic.
12/2
{
AI95-00230-01}
{
AI95-00231-01}
{
AI95-00254-01}
{anonymous access type} {designated
subtype (of an anonymous access type)} {designated
type (of an anonymous access type)} An
access_definition defines an anonymous general
access type or an anonymous access-to-subprogram
type. For a general access type, access-to-variable
type; the
subtype_mark denotes its
designated subtype; if the general_access_modifier
constant appears, the type is an access-to-constant type; otherwise
it is an access-to-variable type. For an access-to-subprogram type, the
parameter_profile or parameter_and_result_profile
denotes its designated profile.{designated
profile (of an anonymous access type)} .
[An access_definition is used in the specification
of an access discriminant (see 3.7) or an access
parameter (see 6.1).]
13/2
{
AI95-00230-01}
{
AI95-00231-01}
{null value (of an access type)}
For each
(named) access
type, there is
a literal null which has
a null access value designating no entity at all
,
which can be obtained by (implicitly) converting the literal null
to the access type. [The null value of
an a
named access type is the default initial value of the type.]
Non-null Other
values of an access
-to-object 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)]
,
or in the case of a general access-to-object type, evaluating an attribute_reference
for the Access or Unchecked_Access attribute of an aliased view of an
object. Non-null values of an access-to-subprogram type are obtained
by evaluating an attribute_reference for the
Access attribute of a non-intrinsic subprogram..
13.a/2
This paragraph
was deleted.Ramification: {
AI95-00231-01}
A value of an anonymous access type (that is, the
value of an access parameter or access discriminant) cannot be null.
13.b/2
This paragraph
was deleted.Reason: {
AI95-00231-01}
Access parameters allow dispatching on the tag
of the object designated by the actual parameter (which gets converted
to the anonymous access type as part of the call). In order for dispatching
to work properly, there had better be such an object. Hence, the type
conversion will raise Constraint_Error if the value of the actual parameter
is null.
13.1/2
{
AI95-00231-01}
{excludes null
(subtype)} A null_exclusion
in a construct specifies that the null value does not belong to the access
subtype defined by the construct, that is, the access subtype excludes
null. In addition, the anonymous access subtype defined by the access_definition
for a controlling access parameter (see 3.9.2)
excludes null. Finally, for a subtype_indication
without a null_exclusion, the subtype denoted
by the subtype_indication excludes null if
and only if the subtype denoted by the subtype_mark
in the subtype_indication excludes null.
13.c/2
Reason: {
AI95-00231-01}
An access_definition
used in a controlling parameter excludes null because it is necessary
to read the tag to dispatch, and null has no tag. We would have preferred
to require not null to be specified for such parameters, but that
would have been too incompatible with Ada 95 code to require.
13.d/2
{
AI95-00416-01}
Note that we considered imposing a similar implicit
null exclusion for controlling access results, but chose not to do that,
because there is no Ada 95 compatibility issue, and there is no automatic
null check inherent in the use of a controlling access result. If a null
check is necessary, it is because there is a dereference of the result,
or because the value is passed to a parameter whose subtype excludes
null. If there is no dereference of the result, a null return value is
perfectly acceptable, and can be a useful indication of a particular
status of the call.
14/1
{
8652/0013}
{
AI95-00012-01}
{constrained (subtype) [partial]}
{unconstrained (subtype)
[partial]} [All subtypes of an access-to-subprogram
type are constrained.] The first subtype of a type defined by an
access_definition access_type_definition
or an
access_to_object_definition is unconstrained
if the designated subtype is an unconstrained array or discriminated
subtype type;
otherwise it is constrained.
14.a
Proof: The Legality Rules on
range_constraints
(see
3.5) do not permit the
subtype_mark
of the
subtype_indication to denote an access-to-scalar
type, only a scalar type. The Legality Rules on
index_constraints
(see
3.6.1) and
discriminant_constraints
(see
3.7.1) both permit access-to-composite
types in a
subtype_indication with such
_constraints.
Note that an access-to-access-to-composite is never permitted in a
subtype_indication
with a
constraint.
14.b/2
Reason: {
AI95-00363-01}
Only
composite_constraints are permitted for
an access type, and only on access-to-composite types. A constraint on
an access-to-scalar or access-to-access type might be violated due to
assignments via other access paths that were not so constrained. By contrast,
if the designated subtype is an array or discriminated type
without defaults, the constraint could not be violated by unconstrained
assignments, since array objects are always constrained, and
aliased
discriminated objects are also constrained
when
the type does not have defaults for its discriminants. Constraints are
not allowed on general access-to-unconstrained discriminated types if
the type has defaults for its discriminants; constraints on pool-specific
access types are usually allowed because allocated objects are usually
constrained by their initial value.(by fiat,
see Static Semantics).
Legality Rules
14.1/2
{
AI95-00231-01}
If a subtype_indication,
discriminant_specification, parameter_specification,
parameter_and_result_profile, object_renaming_declaration,
or formal_object_declaration has a null_exclusion,
the subtype_mark in that construct shall denote
an access subtype that does not exclude null.
14.c/2
To be honest: {
AI95-00231-01}
This means “directly allowed in”; we
are not talking about a null_exclusion that
occurs in an access_definition in one of these
constructs (for an access_definition, the
subtype_mark in such an access_definition
is not restricted).
14.d/2
Reason: {
AI95-00231-01}
This is similar to doubly constraining a composite
subtype, which we also don't allow.
Dynamic Semantics
15/2
{
AI95-00231-01}
{compatibility (composite_constraint
with an access subtype) [partial]} A
composite_constraint
is
compatible with an unconstrained access subtype if it is compatible
with the designated subtype.
A null_exclusion
is compatible with any access subtype that does not exclude null.
{satisfies (for an access value)
[partial]} An access value
satisfies
a
composite_constraint of an access subtype
if it equals the null value of its type or if it designates an object
whose value satisfies the constraint.
An access
value satisfies an exclusion of the null value if it does not equal the
null value of its type.
16
{elaboration (access_type_definition)
[partial]} The elaboration of an
access_type_definition
creates the access type and its first subtype. For an access-to-object
type, this elaboration includes the elaboration of the
subtype_indication,
which creates the designated subtype.
17/2
{
AI95-00230-01}
{
AI95-00254-01}
{elaboration (access_definition)
[partial]} 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)].
18
81 Access values are called “pointers”
or “references” in some other languages.
19
82 Each access-to-object type has an associated
storage pool; several access types can share the same pool. An object
can be created in the storage pool of an access type by an
allocator
(see
4.8) for the access type. A storage pool
(roughly) corresponds to what some other languages call a “heap.”
See
13.11 for a discussion of pools.
20
83 Only
index_constraints
and
discriminant_constraints can be applied
to access types (see
3.6.1 and
3.7.1).
Examples
21
Examples of access-to-object
types:
22/2
{
AI95-00433-01}
type Peripheral_Ref
is not null access Peripheral; --
see 3.8.1
type Binop_Ptr
is access all Binary_Operation'Class;
--
general access-to-class-wide, see 3.9.1
23
Example of an access
subtype:
24
subtype Drum_Ref
is Peripheral_Ref(Drum); --
see 3.8.1
25
Example of an access-to-subprogram
type:
26
type Message_Procedure is access procedure (M : in String := "Error!");
procedure Default_Message_Procedure(M : in String);
Give_Message : Message_Procedure := Default_Message_Procedure'Access;
...
procedure Other_Procedure(M : in String);
...
Give_Message := Other_Procedure'Access;
...
Give_Message("File not found."); -- call with parameter (.all is optional)
Give_Message.all; -- call with no parameters
Extensions to Ada 83
26.a
{
extensions to Ada 83}
The
syntax for
access_type_definition is changed
to support general access types (including access-to-constants) and access-to-subprograms.
The syntax rules for
general_access_modifier
and
access_definition are new.
Wording Changes from Ada 83
26.b
We use the term "storage pool" to
talk about the data area from which allocation takes place. The term
"collection" is no longer used. ("Collection" and
"storage pool" are not the same thing because multiple unrelated
access types can share the same storage pool; see
13.11
for more discussion.)
Inconsistencies With Ada 95
26.c/2
{
AI95-00231-01}
{inconsistencies with Ada 95} Access
discriminants and non-controlling access parameters no longer exclude
null. A program which passed null to such an access discriminant
or access parameter and expected it to raise Constraint_Error may fail
when compiled with Ada 2005. One hopes that there no such programs outside
of the ACATS. (Of course, a program which actually wants to pass null
will work, which is far more likely.)
26.d/2
{
AI95-00363-01}
Most unconstrained aliased objects with defaulted
discriminants are no longer constrained by their initial values. This
means that a program that raised Constraint_Error from an attempt to
change the discriminants will no longer do so. The change only affects
programs that depended on the raising of Constraint_Error in this case,
so the inconsistency is unlikely to occur outside of the ACATS. This
change may however cause compilers to implement these objects differently,
possibly taking additional memory or time. This is unlikely to be worse
than the differences caused by any major compiler upgrade.
Incompatibilities With Ada 95
26.e/2
{
AI95-00225-01}
{incompatibilities with Ada 95} Amendment
Correction: The rule defining when a current instance of a limited
type is considered to be aliased has been tightened to apply only to
types that cannot become nonlimited. A program that attempts to take
'Access of the current instance of a limited type that can become nonlimited
will be illegal in Ada 2005. While original Ada 95 allowed the current
instance of any limited type to be treated as aliased, this was inconsistently
implemented in compilers, and was likely to not work as expected for
types that are ultimately nonlimited.
Extensions to Ada 95
26.f/2
{
AI95-00231-01}
{extensions to Ada 95} The
null_exclusion is new. It can be used in both
anonymous and named access type definitions. It is most useful to declare
that parameters cannot be null, thus eliminating the need for
checks on use.
26.g/2
{
AI95-00231-01}
{
AI95-00254-01}
{
AI95-00404-01}
The kinds of anonymous access types allowed were
increased by adding anonymous access-to-constant and anonymous access-to-subprogram
types. Anonymous access-to-subprogram types used as parameters allow
passing of subprograms at any level.
Wording Changes from Ada 95
26.h/2
{
8652/0012}
{
AI95-00062-01}
Corrigendum: Added accidentally-omitted
wording that says that a derived access type shares its storage pool
with its parent type. This was clearly intended, both because of a note
in 3.4, and because anything else would have
been incompatible with Ada 83.
26.i/2
{
8652/0013}
{
AI95-00012-01}
Corrigendum: Fixed typographical errors
in the description of when access types are constrained.
26.j/2
{
AI95-00230-01}
The wording was fixed to allow allocators
and the literal null for anonymous access types. The former was
clearly intended by Ada 95; see the Implementation Advice in 13.11.
26.k/2
{
AI95-00363-01}
The rules about aliased objects being constrained
by their initial values now apply only to allocated objects, and thus
have been moved to 4.8, “Allocators”.