!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 <> 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. *************************************************************