Version 1.1 of ais/ai-00230.txt
!standard 10.1.2 (01) 00-04-13 AI95-00230/01
!class amendment 00-04-13
!status work item 00-04-13
!status received 00-04-13
!priority Medium
!difficulty Hard
!subject Implicit conversions between access types
!summary
A new attribute Class_Access is proposed to provide access type
"substitutability" (see !discussion) in more contexts than that provided
by the "access T'Class" parameter.
!problem
This proposal attempts to resolve a problem encountered when
creating Ada packages to use in interfacing 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.
!proposal
T'Class_Access where T is a specific tagged type, denotes a general
access-to-variable type with designated type T'Class, implicitly
declared at the same place where the type T is declared. It has predefined
"=" and "/=" operators. It's storage pool has size 0, resulting in
Storage_Error on any allocator.
RM95 8.6(22,5) is amended as follows:
When the expected type for a construct is T'Class_Access, the
type of the construct shall resolve to an access type whose designated
type is covered by T'Class.
!wording
(See proposal.)
!example
!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).
Explicit access type conversions can be used to provide the desired
substitutability, but scattering type conversions around muddies the waters,
and makes it harder to find the few type conversions that are really
"significant."
This AI proposes a new attribute, T'Class_Access that is analogous to
T'Class, and can be used for the type of potentially-null parameters,
array and record components, declared objects, etc. It avoids introducing
any new syntax and avoids any incompatibility issues by not changing the
implicit conversion rules for existing 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 general access-to-classwide 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.
!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.
*************************************************************
Questions? Ask the ACAA Technical Agent