!standard 4.6(24.17/3) 13-05-08 AI12-0027-1/06 !standard 4.6(24.21/2) !standard 4.6(58) !standard 6.2(10/3) !standard 3.10.2(10/3) !class binding interpretation 12-06-04 !status Corrigendum 1-2012 12-12-31 !status WG9 Approved 13-06-14 !status ARG Approved 8-0-2 12-12-08 !status work item 12-06-04 !status received 12-04-09 !priority Medium !difficulty Medium !subject Access values should never designate unaliased components !summary Composite value conversions can cause a copy of the operand object to be made; as such, the accessibility level of such conversions is usually local. !question We don't want access values pointing to unaliased objects. But there appear to be several ways to create such values. 4.6(24.8) prohibits view conversions from array types with unaliased components to array types with aliased components. However, value conversions can also create such components. Consider: type T is tagged null record; type Rec is record F1 : T; F2 : Integer; end record; type Rec_Ref is access constant Rec; Ptr : Rec_Ref; subtype Index is Integer range 1 .. 3; type A1 is array (Index) of Rec; type A2 is array (Index) of aliased Rec; X1 : A1; begin Ptr := A2 (X1)(Index'First)'Access; -- Ptr now designates an unaliased object In addition, the existing wording doesn't deal with contract model issues with generics. By 12.5.3(8) and AARM 12.5.3(8.a), it's OK if a formal array type's components are unaliased and the actual's are aliased, and Legality Rules such as 4.6(24.8) aren't checked in an instance body. !recommendation (See summary.) !wording Append to the end of the Legality Rules section of 4.6 (after 24.p/2): In addition to the places where Legality Rules normally apply (see 12.3), these rules apply also in the private part of an instance of a generic unit. Remove the existing occurrences of the above wording from 4.6(24.17/3) and 4.6(24.21/2) as the above covers them. Append at the end of Dynamic Semantics section of 4.6: Evaluation of a value conversion of a composite type either creates a new anonymous object [Redundant:(similar to the object created by the evaluation of an aggregate or a function call)] or yields a new view of the operand object without creating a new object: - If the target type is a by-reference type and there is a type that is an ancestor of both the target type and the operand type then no new object is created; - If the target type is an array type having aliased components and the operand type is an array type having unaliased components, then a new object is created; - Otherwise, it is unspecified whether a new object is created. If a new object is created, then the initialization of that object is an assignment operation. AARM note: This makes a difference in the case of converting from an array type with unaliased components to one with aliased components if the element type has a controlled part. Append to the end of 3.10.2(10/3): Corresponding rules apply to a value conversion (see 4.6). In 6.2(10/3), replace For a parenthesized expression, qualified_expression, or type_conversion, this object is the one associated with the operand. with For a parenthesized expression, qualified_expression, or view conversion, this object is the one associated with the operand. For a value conversion, the associated object is the anonymous result object if such an object is created (see 4.6); otherwise it is the associated object of the operand. !discussion Ada 2012 never defines the accessibility of value conversions. However, these are expected to be able to change representations (as described in 13.6), and such a change surely will require a copy. If the type contains aliased components, surely those will need to be copied, too. Thus, simply designing a rule to make cases like the one in the question directly illegal doesn't fix anything. Moreover, as it needs to be enforced in an assume-the-worst manner in generic bodies, it could make existing code that has no problem illegal. That doesn't seem very promising. Rather, we explicitly define the copying done by a value conversion, and define the accessibility of such a conversion when it is copied to be similar to that for an aggregate defined in the same place. That will give such components a very short lifetime such that most attempts to take 'Access of them will fail an accessibility check. As most such checks are made statically, this will not add much overhead. !corrigendum 3.10.2(10/3) @drepl @xbullet that is used (in its entirety) to directly initialize part of an object is that of the object being initialized. In other contexts, the accessibility level of an @fa is that of the innermost master that evaluates the @fa.> @dby @xbullet that is used (in its entirety) to directly initialize part of an object is that of the object being initialized. In other contexts, the accessibility level of an @fa is that of the innermost master that evaluates the @fa. Corresponding rules apply to a value conversion (see 4.6).> !corrigendum 4.6(24.17/3) @drepl @xinbull @dby @xinbull !corrigendum 4.6(24.21/2) @drepl @xinbull @dby @xinbull In addition to the places where Legality Rules normally apply (see 12.3), these rules apply also in the private part of an instance of a generic unit. !corrigendum 4.6(58) @dinsa Conversion to a type is the same as conversion to an unconstrained subtype of the type. @dinss Evaluation of a value conversion of a composite type either creates a new anonymous object (similar to the object created by the evaluation of an @fa or a function call) or yields a new view of the operand object without creating a new object: @xbullet @xbullet @xbullet If a new object is created, then the initialization of that object is an assignment operation. !corrigendum 6.2(10/3) @drepl A parameter of a by-reference type is passed by reference, as is an explicitly aliased parameter of any type. Each value of a by-reference type has an associated object. For a parenthesized expression, @fa, or @fa, this object is the one associated with the operand. For a @fa, this object is the one associated with the evaluated @i@fa. @dby A parameter of a by-reference type is passed by reference, as is an explicitly aliased parameter of any type. Each value of a by-reference type has an associated object. For a parenthesized expression, @fa, or view conversion, this object is the one associated with the operand. For a value conversion, the associated object is the anonymous result object if such an object is created (see 4.6); otherwise it is the associated object of the operand. For a @fa, this object is the one associated with the evaluated @i@fa. !ACATS test An ACATS B-Test (using static accessibility) should be created to test these rules. !ASIS No ASIS impact. !appendix !topic Aliased components: generic contract model violation? !reference 4.6(24.8), 4.6(8), 12.5.3(8) !from Adam Beneschan 12-04-09 !discussion Consider: ------------------------------------------------------------------------------- package Pack1 is type T (D : Integer := 0) is null record; type T_Arr is array (Natural range <>) of T; -- unaliased components procedure Increment_Discriminant (Arr : in out T_Arr; Index : Natural); end Pack1; package body Pack1 is procedure Increment_Discriminant (Arr : in out T_Arr; Index : Natural) is begin Arr (Index) := (D => Arr (Index).D + 1); end Increment_Discriminant; end Pack1; with Pack1; package Pack2 is type My_Arr is array (Natural range <>) of aliased Pack1.T; end Pack2; with Pack2; package Pack3 is procedure Illegal (Arr : in out Pack2.My_Arr; Index : Natural); end Pack3; with Pack1; package body Pack3 is procedure Illegal (Arr : in out Pack2.My_Arr; Index : Natural) is begin Pack1.Increment_Discriminant (Pack1.T_Arr (Arr), Index); -- view conversion illegal by 4.6(24.8) and 4.6(8) end Illegal; end Pack3; with Pack1; generic type Formal_Arr is array (Natural range <>) of Pack1.T; package Pack4 is procedure Mess_With (Arr : in out Formal_Arr; Index : Natural); end Pack4; package body Pack4 is procedure Mess_With (Arr : in out Formal_Arr; Index : Natural) is begin Pack1.Increment_Discriminant (Pack1.T_Arr (Arr), Index); end Mess_With; end Pack4; with Pack2; with Pack4; package Pack5 is package New_Pack4 is new Pack4 (Pack2.My_Arr); -- generic contract model violation? end Pack5; ------------------------------------------------------------------------------- As I understand it, a rule was added in AI95-168 and AI95-363 to prohibit type conversions from array types with unaliased components to array types with aliased components (4.6(24.8)), in order to prevent the discriminant of an aliased discriminated component from being modified. 4.6(8) says that for a view conversion used as an OUT or IN OUT actual parameter, the types have to be convertible both ways, which means that an array type with aliased components can't be converted to an array type with unaliased components either. This makes the type conversion in the body of Pack3 illegal, which is the desired behavior since otherwise the discriminant of an aliased component of My_Arr would be modified. Did I understand this correctly? However, it seems that you can get around this by using generics, since by 12.5.3(8) and AARM 12.5.3(8.a) it's OK if a formal array type's components are unaliased and the actual's are aliased, and Legality Rules such as 4.6(24.8) aren't checked in an instance body. **************************************************************** From: Steve Baird Sent: Sunday, July 15, 2012 8:55 PM Here is proposed wording and a little bit of discussion. Thanks to Gary for valuable review. -- Steve AI12-0027 !wording append to 4.6(8/2): 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. TBD: do we need similar boilerplate for 21/3 and 24/3? Let's wait until a need is demonstrated. append after 4.6(24.8/2), as another bulleted list item: - if the Target_Type of a view conversion is a generic formal array type of a generic unit G that does not have aliased components, then the conversion shall not occur within the body of G, nor within the body of a generic unit declared within the declarative region of G. TBD: this is the 4th occurrence of this somewhat opaque "within the body of a of a generic unit declared within" wording. See 8.5.1, 8.5.4, and 12.6. Do we want to define a term like "the extended body" of a generic unit and then use that term in these 4 places? ===== I think the above wording change addresses the problem Adam identified. But what about the case of a non-view conversion when the element type of the array is a by-reference type? It looks like the RM authors assumed that this is only a problem in the view conversion case. See AARM 4.6 (24.d/2). But 6.2(10/3) says: Each value of a by-reference type has an associated object. For a parenthesized expression, qualified_expression, or type_conversion, this object is the one associated with the operand. For a conditional_expression, this object is the one associated with the evaluated dependent_expression. We don't want access values pointing to unaliased objects. Consider type T is tagged null record; type Rec is record F1 : T; F2 : Integer; end record; type Rec_Ref is access constant Rec; Ptr : Rec_Ref; subtype Index is Integer range 1 .. 3; type A1 is array (Index) of Rec; type A2 is array (Index) of aliased Rec; X1 : A1; begin Ptr := A2 (X1)(Index'First)'Access; -- Ptr now designates an unaliased object Maybe this is a separate problem that we don't need to worry about in the context of this AI. **************************************************************** From: Randy Brukardt Sent: Monday, July 16, 2012 8:38 PM > !wording > > append to 4.6(8/2): > 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. > > TBD: do we need similar boilerplate for 21/3 and 24/3? Let's wait > until a need is demonstrated. The meta-rule for the boilerplate is that it is used for all Legality Rules, unless: (1) The rule cannot depend on generic formal entities; or (2) There is a reason that we do not want the rule enforced in private parts (only one known case of this). As such, I would expect the boilerplate to apply to all of the rules in 4.6. I can't quite imagine why we would want to allow an illegal type conversion just because it was in a private part. Most of the rules can't change in a private part (such as the dimensionality of an array type), but it's just too much work to figure out which ones can and can't differ in the generic and the instance (that is, between the formal and the actual). So I would put this boilerplate after 4.6(24.21/2) and make it apply to the entire legality rules section (we did something like this in 4.8, so steal that wording). We should let the implementers and/or testers figure out when it matters. > append after 4.6(24.8/2), as another bulleted list item: > > - if the Target_Type of a view conversion is a generic formal array > type of a generic unit G that does not have aliased components, then > the conversion shall not occur within the body of G, nor within the > body of a generic unit declared within the declarative region of G. > > TBD: this is the 4th occurrence of this somewhat opaque "within the > body of a of a generic unit declared within" wording. See 8.5.1, > 8.5.4, and 12.6. Do we want to define a term like "the extended > body" of a generic unit and then use that term in these 4 places? Does that really help anything? I'm dubious that "extended body" says anything clearer. It's really talking about related generic children and nested units. This wording at least makes it obvious that we're including units that are inside the generic. Maybe if you came up with a term that evoked bodies of child and nested units. > ===== > > I think the above wording change addresses the problem Adam identified. > But what about the case of a non-view conversion when the element type > of the array is a by-reference type? I don't see a separate problem for "by-reference". A non-view conversion always has to be illegal in such a case (see below). > It looks like the RM authors assumed that this is only a problem in > the view conversion case. See AARM 4.6 (24.d/2). > > But 6.2(10/3) says: > Each value of a by-reference type has an associated object. For a > parenthesized expression, qualified_expression, or type_conversion, > this object is the one associated with the operand. For a > conditional_expression, this object is the one associated with the > evaluated dependent_expression. > > We don't want access values pointing to unaliased objects. > > Consider > > type T is tagged null record; > > type Rec is record F1 : T; F2 : Integer; end record; > > type Rec_Ref is access constant Rec; > Ptr : Rec_Ref; > > subtype Index is Integer range 1 .. 3; > > type A1 is array (Index) of Rec; > type A2 is array (Index) of aliased Rec; > > X1 : A1; > begin > Ptr := A2 (X1)(Index'First)'Access; > -- Ptr now designates an unaliased object I don't think the above is (or should be) legal, for reasons unrelated to your point. (1) The model appears to be that value (not-view) type conversions are always logically copies. Notes like 4.6(24.e/2) reinforce this view (the intent being that a value conversion can change representations of by-reference components. As such, by-reference has no effect here. This means that 6.2(10/3) should only be talking about view conversions, not all type_conversions. (Yes, there is an object associated with the by-reference components, but there ought to be nothing that requires it to be the *same* object as in the operand object.) I think the authors of 6.2(10/3) expected that all type conversions of by-reference types be view conversions, but that is not achieved. (2) If the expectation is that 6.2(10/3) is in fact correct, then *all* of the rules in 4.6 have to be rechecked, because virtually every rule that applies to a view conversion also would have to apply to a conversion of a by-reference type. An obvious example is 4.6(24.9/2), which specifically expects value conversions to be able to use by-copy to reconcile representation differences. type A3 is array (Index) of Rec with Component_Size => Rec'Size*2; procedure Proc3 (P : A3); Proc3 (A3 (X1)); -- By-copy better be allowed The compiler probably has no reason to reject either A1 or A3 or the value conversion between them, so how does the representation change get accomplished?? (3) If this type conversion is implemented by-copy, then there is a very local object created to hold the result of the conversion. (One would expect the master to be that of the statement.) One would hope that such an object would fail an accessibility check (taking 'Access of a very local object and putting it into a more global type should never be allowed). (By-copy certainly should be allowed in the non-by-reference case, so this is true no matter what the answer to (1) and (2) are). (4) We don't want accessibility checks to depend on implementation choices, so this check should apply to all value type conversions to target types with aliased components. So the above should be illegal as it fails an accessibility check. (I don't have the ambition to dig around in the Heart of Darkness to find out if this is already true or if there is yet-another-hole in the accessibility rules.) (5) One could make this not-necessarily-illegal by passing the 'Access as an access parameter. Then the too-short lifetime of the copy would not be a problem. That would look like: procedure Proc (P : access constant Rec); Proc (A2 (X1)(Index'First)'Access); (6) The remaining question is whether the above case is worth allowing in the rare case that the accessibility would work. I think not (and this allows avoiding a trip to the Heart of Darkness). So probably the word "view" should be dropped from 4.6(24.9/2). (7) But note that there is likely a similar accessibility problem for a value conversion to a record type with aliased components. Even though the type is related (and thus there is no change of "aliased" for the components), we still will be making a copy, and that should have a short lifetime. And that also would happen when converting between two array types with aliased components in a value conversion. > Maybe this is a separate problem that we don't need to worry about in > the context of this AI. Right, it doesn't belong to this AI. But perhaps you ought to write up the AI that it does belong to. :-) **************************************************************** From: Steve Baird Sent: Tuesday, July 17, 2012 4:54 PM ... > So I would put this boilerplate after 4.6(24.21/2) and make it apply > to the entire legality rules section (we did something like this in > 4.8, so steal that wording). > Fine with me. >> append after 4.6(24.8/2), as another bulleted list item: >> >> - if the Target_Type of a view conversion is a generic formal array >> type of a generic unit G that does not have aliased components, then >> the conversion shall not occur within the body of G, nor within the >> body of a generic unit declared within the declarative region of G. >> >> TBD: this is the 4th occurrence of this somewhat opaque "within the >> body of a of a generic unit declared within" wording. See 8.5.1, >> 8.5.4, and 12.6. Do we want to define a term like "the extended >> body" of a generic unit and then use that term in these 4 places? > > Does that really help anything? I'm dubious that "extended body" says > anything clearer. It's really talking about related generic children > and nested units. This wording at least makes it obvious that we're > including units that are inside the generic. Maybe if you came up with > a term that evoked bodies of child and nested units. I agree that "extended body" is not a great name for this idea; it was intended more as a placeholder until someone came up with a better name. But even if we called it "Scooby Doo Where Are You?", it would still have the advantage of consolidating what would otherwise be four copies of this subtle wording. > So probably the word "view" should be dropped from 4.6(24.9/2). I agree, although I think we'd want to delete the phrase "of a view conversion" (see, for example, 24.7/2's use of "the operand type"). I read 13.1(10/3) as supporting this change - it suggests that it was intended that a type conversion for a by-reference type should never have to make a copy. I think this is not just eisegesis on my part. There is, however, the argument that this is too much of an incompatibility (it would disallow some conversions that are currently legal). Instead, one might argue, we could go with the "short-lived copy" model that you outlined. This would require 1) Modifying 6.2(10/3) to know about this exception to the rule that the associated object of a type conversion is that of the operand. 2) Modifying 3.10.2 to define the accessibility level of this copy, probably by somehow piggybacking on the existing wording for aggregates. This may need to be done in any case - as I read 3.10.2, I found no definition for the accessibility level of the result of a non-view type conversion. But it would also require, I think, RM wording to deal with controlled subcomponents of the copies and I don't think we want to allow such copying. I think we really want to stick with the rule that a conversion of a by-reference type never makes a copy. Begin side-topic discussion: 4.6(24.9/2) correctly uses the wording "tagged, private, or volatile" to capture the idea of a type that "might be by-reference". I think this is the sort of wording that is needed when talking about by-reference types in the context of static semantics. 13.1(10/3) doesn't do this. It just says For an untagged derived type, it is illegal to specify a type-related representation aspect if the parent type is a by-reference type, or .... Is this wording really ok? I know that legality checking for representation aspect specifications ignores privacy, but suppose you are in the body of a generic package and you have a component of a formal private type. Does the rule apply? We want it to, but it's not clear that the current wording captures this intent. Can we fix that wording to follow the example of 4.6(24.9/2) as part of this AI? end side-topic discussion > (7) But note that there is likely a similar accessibility problem for > a value conversion to a record type with aliased components. Even > though the type is related (and thus there is no change of "aliased" > for the components), we still will be making a copy, and that should > have a short lifetime. And that also would happen when converting > between two array types with aliased components in a value conversion. So 6.2(10/3) needs to know that some type conversions make copies and 3.10.2 needs to define the accessibility level of these copies. If we have to do this work anyway, then that slightly weakens the argument for incompatibly tightening up 4.6(24.9/2). Still, I think the issue with copying controlled parts is enough by itself to justify this change. >> Maybe this is a separate problem that we don't need to worry about in >> the context of this AI. > > Right, it doesn't belong to this AI. But perhaps you ought to write up > the AI that it does belong to. :-) Ok. At this point, I'm just trying to get consensus on intent. **************************************************************** From: Randy Brukardt Sent: Tuesday, July 17, 2012 5:39 PM ... > >> append after 4.6(24.8/2), as another bulleted list item: > >> > >> - if the Target_Type of a view conversion is a generic formal array > >> type of a generic unit G that does not have aliased components, then > >> the conversion shall not occur within the body of G, nor within the > >> body of a generic unit declared within the declarative region of G. > >> > >> TBD: this is the 4th occurrence of this somewhat opaque "within the > >> body of a of a generic unit declared within" wording. See 8.5.1, > >> 8.5.4, and 12.6. Do we want to define a term like "the extended > >> body" of a generic unit and then use that term in these 4 places? > > > > Does that really help anything? I'm dubious that "extended body" > > says anything clearer. It's really talking about related generic > > children and nested units. This wording at least makes it obvious > > that we're including units that are inside the generic. Maybe if you > > came up with a term that evoked bodies of child and nested units. > > I agree that "extended body" is not a great name for this idea; it was > intended more as a placeholder until someone came up with a better name. > But even if we called it "Scooby Doo Where Are You?", it would still > have the advantage of consolidating what would otherwise be four > copies of this subtle wording. I don't see any benefit to replacing subtle wording with a rarely used term (which will have to be looked up). That could only have a benefit to the reader if the term evoked the correct semantics (but still is obviously a defined term - we don't want a replay of the "part" fiasco). Usually, the subtle wording is long and replacing it with a term helps because it avoids repeating a long description. But this would only replace a handful of words - the only real advantage is avoiding copying the associated AARM note, and I don't think we should be designing wording solely to simplify the *AARM*. ... > > So probably the word "view" should be dropped from 4.6(24.9/2). > > I agree, although I think we'd want to delete the phrase "of a view > conversion" (see, for example, 24.7/2's use of "the operand type"). > > I read 13.1(10/3) as supporting this change - it suggests that it was > intended that a type conversion for a by-reference type should never > have to make a copy. I think this is not just eisegesis on my part. I guess I can buy that. That gives two paragraphs that imply that a value conversion of a by-reference type never makes a copy (6.2, 13.1). (Of course, the problem is that in the current case, 13.1(10/3) provides no protection, because the array types are not related.) > There is, however, the argument that this is too much of an > incompatibility (it would disallow some conversions that are currently > legal). Right. Argubly, these are conversions that should never have been allowed, and they're pretty rare. But, as I noted below, this doesn't really fix the problem (at least not completely). > Instead, one might argue, we could go with the "short-lived copy" > model that you outlined. > > This would require > 1) Modifying 6.2(10/3) to know about this exception to > the rule that the associated object of a type conversion > is that of the operand. > 2) Modifying 3.10.2 to define the accessibility level of this > copy, probably by somehow piggybacking on the existing > wording for aggregates. This may need to be done > in any case - as I read 3.10.2, I found no definition > for the accessibility level of the result of a non-view > type conversion. > > But it would also require, I think, RM wording to deal with controlled > subcomponents of the copies and I don't think we want to allow such > copying. > > I think we really want to stick with the rule that a conversion of a > by-reference type never makes a copy. I think that's OK, which means deleting "view conversion" from 4.6(24.9/2). But we have to "go with the short-lived copy model" because there are certainly types that are not by-reference and require copying. > Begin side-topic discussion: > 4.6(24.9/2) correctly uses the wording > "tagged, private, or volatile" to capture the > idea of a type that "might be by-reference". > I think this is the sort of wording that is > needed when talking about by-reference > types in the context of static semantics. > 13.1(10/3) doesn't do this. It just says > For an untagged derived type, it is illegal to specify > a type-related representation aspect if the parent type > is a by-reference type, or .... > > Is this wording really ok? I know that legality checking > for representation aspect specifications ignores privacy, but > suppose you are in the body of a generic package and you > have a component of a formal private type. Does the rule apply? > We want it to, but it's not clear that the current wording > captures this intent. Can we fix that wording to follow > the example of 4.6(24.9/2) as part of this AI? > end side-topic discussion Specifying type-related aspects for a type derived from a generic formal type is illegal (see 13.1(11/3), so I don't think we ever get to 13.1(10/3) in that case. How else could this happen? I suppose you could define a record type in the generic specification and then immediately derive from it, but that is such a silly thing to do that it hardly is worth worrying about. Moreover, virtually all representation aspects are not required (in "RLS") on types with components of a formal type, so this can only be a problem if the implementation wants it to be a problem. And we already know there are many stupid things that an implementation can try to support; this is clearly another. So I don't see a problem here that is worth fixing (especially at a compatibility cost) unless you can find an example that falls under the RLS (and in that case, the RLS is probably wrong). > > (7) But note that there is likely a similar accessibility problem > > for a value conversion to a record type with aliased components. > > Even though the type is related (and thus there is no change of "aliased" > > for the components), we still will be making a copy, and that should > > have a short lifetime. And that also would happen when converting > > between two array types with aliased components in a value conversion. > > So 6.2(10/3) needs to know that some type conversions make copies and > 3.10.2 needs to define the accessibility level of these copies. I don't think 6.2(10/3) is involved; it is only talking about by-reference types, and in the above I'm talking only about types that are *not* by-reference types. (We covered them previously, and you want to make those illegal for good reason.) But 3.10.2 is certainly involved. And we can't eliminate this case unless we eliminate the entire idea of "Change of Representation" (as described in 13.6) for composite types. We're pretty close as it is (it is hard to write an example where "Change of Representation" actually works). > If we have to do this work anyway, then that slightly weakens the > argument for incompatibly tightening up 4.6(24.9/2). > > Still, I think the issue with copying controlled parts is enough by > itself to justify this change. Sure, make the by-reference cases illegal. But we still have to define the accessibility for types that are not by-reference, as those conversions can make a copy. Example: type Rec1 is record A : aliased Integer; C : Character; end record; for Rec1 use record A at 0 range 0 .. 31; C at 4 range 0 .. 7; end record; type Rec2 is new Rec1; for Rec2 use record A at 4 range 0 .. 31; C at 0 range 0 .. 7; end record; procedure Bar (P : access Integer); R1 : Rec1; Bar (Rec2(R1).A'Access); We can also construct similar cases using unrelated array types (for which there is no possibility of something like 13.1(10/3) to save us). The only alternative would be to make all types with aliased components be "by-reference". Maybe that would have been a good idea, but it would be quite incompatible these days (given the number of legality rules that it would trigger). > >> Maybe this is a separate problem that we don't need to worry about > >> in the context of this AI. > > > > Right, it doesn't belong to this AI. But perhaps you ought to write > > up the AI that it does belong to. :-) > > Ok. At this point, I'm just trying to get consensus on intent. You've got mine above. Hopefully others will weight in as well. **************************************************************** From: Tucker Taft Sent: Tuesday, July 17, 2012 5:58 PM I'm not convinced either way yet about whether value conversions of by-reference types are always by-reference. I would hold off on writing this up until we have more e-mail discussion and reach some kind of consensus. **************************************************************** From: Steve Baird Sent: Tuesday, July 17, 2012 6:22 PM > I don't see any benefit to replacing subtle wording with a rarely used > term (which will have to be looked up). I think you left out something important when you said 'subtle wording", not "four copies of subtle wording". But I see your point - there is a lot more benefit to defining a new term if the new term has a good name. >> I think we really want to stick with the rule that a conversion of a >> by-reference type never makes a copy. > > I think that's OK, which means deleting "view conversion" from 4.6(24.9/2). > But we have to "go with the short-lived copy model" because there are > certainly types that are not by-reference and require copying. Agreed, but the not-by-reference guys don't introduce the problem I was worried about with controlled parts. >> Begin side-topic discussion: >> 4.6(24.9/2) correctly uses the wording >> "tagged, private, or volatile" to capture the >> idea of a type that "might be by-reference". >> I think this is the sort of wording that is >> needed when talking about by-reference >> types in the context of static semantics. >> 13.1(10/3) doesn't do this. It just says >> For an untagged derived type, it is illegal to specify >> a type-related representation aspect if the parent type >> is a by-reference type, or .... >> >> Is this wording really ok? I know that legality checking >> for representation aspect specifications ignores privacy, but >> suppose you are in the body of a generic package and you >> have a component of a formal private type. Does the rule apply? >> We want it to, but it's not clear that the current wording >> captures this intent. Can we fix that wording to follow >> the example of 4.6(24.9/2) as part of this AI? >> end side-topic discussion > > Specifying type-related aspects for a type derived from a generic > formal type is illegal (see 13.1(11/3), so I don't think we ever get > to 13.1(10/3) in that case. How else could this happen? I think you misunderstood me. I'm not talking about deriving from a generic formal type. I'm talking about deriving from, say, a record type that has a generic formal private component where that component will determine whether the record type is a by-reference type. > I suppose you could define a > record type in the generic specification and then immediately derive > from it, No, not immediately. The derivation occurs in the generic body. And the parent type could be declared either in the spec or the body. A more plausible example might be generic type Element is private; package G is type Vec is array (Positive range <>) of Element; ... end G; package body G is type Packed_Vec is new Vec with Pack; ... end G; But maybe this is a bad example because if Element turns out to be a by-reference type, then Packed_Vec will probably have the same representation as Vec. Anyhow, you get the idea. > but that is such a silly thing to do that it hardly is worth worrying > about. So you think there is a wording problem, but not one worth fixing? Ok by me. > Moreover, virtually all representation aspects are not required (in > "RLS") on types with components of a formal type, so this can only be > a problem if the implementation wants it to be a problem. And we > already know there are many stupid things that an implementation can > try to support; this is clearly another. So I don't see a problem here > that is worth fixing (especially at a compatibility cost) unless you > can find an example that falls under the RLS (and in that case, the RLS > is probably wrong). I got lost here. Whatever are you talking about? >> So 6.2(10/3) needs to know that some type conversions make copies and >> 3.10.2 needs to define the accessibility level of these copies. > > I don't think 6.2(10/3) is involved; it is only talking about > by-reference types, and in the above I'm talking only about types that > are *not* by-reference types. (We covered them previously, and you > want to make those illegal for good reason.) OK. > But 3.10.2 is certainly involved. Didn't Anita Bryant once say that an AI without a 3.10.2 change is like a day without sunshine? Perhaps I'm misremembering her exact words. > Sure, make the by-reference cases illegal. But we still have to define > the accessibility for types that are not by-reference, as those > conversions can make a copy. Agreed. **************************************************************** From: Randy Brukardt Sent: Tuesday, July 17, 2012 7:16 PM > > I don't see any benefit to replacing subtle wording with a rarely > > used term (which will have to be looked up). > > I think you left out something important when you said 'subtle > wording", not "four copies of subtle wording". And you left out something important when I noted that the "subtle wording" only adds a dozen or so words over what a term would. Using a "term" here would make the Standard longer, and it's unclear that it would improve the understandability at all. > But I see your point - there is a lot more benefit to defining a new > term if the new term has a good name. ... > >> I think we really want to stick with the rule that a conversion of > >> a by-reference type never makes a copy. > > > > I think that's OK, which means deleting "view conversion" from 4.6(24.9/2). > > But we have to "go with the short-lived copy model" because there > > are certainly types that are not by-reference and require copying. > > Agreed, but the not-by-reference guys don't introduce the problem I > was worried about with controlled parts. Right, I agree with that. Note, however, that once the accessibility is properly defined, then the controlled part rules fall out for free. So I don't see a big issue here. (There is an implementation cost, of course, which is a legitimate concern.) ... > > I suppose you could define a > > record type in the generic specification and then immediately derive > > from it, > > No, not immediately. The derivation occurs in the generic body. > And the parent type could be declared either in the spec or the body. > > A more plausible example might be > > generic > type Element is private; > package G is > type Vec is array (Positive range <>) of Element; > ... > end G; > package body G is > type Packed_Vec is new Vec with Pack; > ... > end G; > > But maybe this is a bad example because if Element turns out to be a > by-reference type, then Packed_Vec will probably have the same > representation as Vec. Right; that's my second point: it's never required to support something that would cause any trouble. Pack in this situation is either ignored or illegal (depending on the implementation). Neither can cause trouble. > Anyhow, you get the idea. > > > but that is such a silly thing to do that it hardly is worth > > worrying about. > > So you think there is a wording problem, but not one worth fixing? > Ok by me. I'm unconvinced that the "wording problem" could ever matter in practice. > > Moreover, virtually all representation aspects are not required (in > > "RLS") on types with components of a formal type, so this can only > > be a problem if the implementation wants it to be a problem. And we > > already know there are many stupid things that an implementation can > > try to support; this is clearly another. So I don't see a problem > > here that is worth fixing (especially at a compatibility cost) > > unless you can find an example that falls under the RLS (and in that > > case, the RLS is probably wrong). > > I got lost here. Whatever are you talking about? "RLS" = Recommended Level of Support. There is no case where the RLS requires supporting anything when the component is a generic formal type. (At least, there ought not be; you don't know the size or alignment involved, and generic bodies are always "assume-the-worst". I don't know what you *could* specify.) I don't care if an implementer wants to shoot themselves in the head by supporting something that would require copying by-reference objects. It only matters if the language requires such support. Ada has many things (especially involving alignment) that cannot sanely be supported, and we don't try to make them illegal. So it does not matter if there is one more such case. It only matters if the RLS requires supporting something which would be impossible to implement for a by-reference type (assuming we don't require copies for value conversions). BTW, note that changing 13.1(10/3) as you suggest would be wildly incompatible, as it would apply to all private types (not just formal private types). I don't think we want to change this unless there is a *real* problem, not just one in Steve's mind. ... > > But 3.10.2 is certainly involved. > > Didn't Anita Bryant once say that an AI without a 3.10.2 change is > like a day without sunshine? Perhaps I'm misremembering her exact > words. Uh-huh. **************************************************************** From: Steve Baird Sent: Wednesday, July 18, 2012 1:19 PM > I'm not convinced either way yet about whether value conversions of > by-reference types are always by-reference. I would hold off on > writing this up until we have more e-mail discussion and reach some > kind of consensus. Sounds like a good approach. **************************************************************** From: Randy Brukardt Sent: Wednesday, July 18, 2012 1:45 PM I'd expect you to say that, because it makes less work for you. ;-) I agree that we need more discussion; in particular, we need other ARG members to join these discussions that seem to be mainly between Steve and I. But we know from experience that if that doesn't happen soon, then we have to write up what we have in order to stimulate a new discussion. So Steve should not get too comfortable in avoiding a write-up. :-) **************************************************************** From: Tucker Taft Sent: Wednesday, July 18, 2012 2:08 PM > Sounds like a good approach. Could you summarize, for those of us who have not been following this debate closely, exactly what are the indications in the RM for and against this rule about requiring value conversions of by-reference types to be by-reference? **************************************************************** From: Randy Brukardt Sent: Wednesday, July 18, 2012 2:44 PM IMHO, this is a secondary question. (It started out as the primary question, and probably ought to remain the primary question of the AI above, but there is a more important question that needs to be answered and could change the answer to the above.) We all agree (I hope) that some type conversions involve copying. The problem is that the accessibility rules don't, so far as I can tell, take this copying into account. This is irrespective of whether by-reference types can be copied or not, as aliased components don't make a type by-reference. (Perhaps they should have, but it is way too late for that sort of change, as it would have severe compatibility effects.) Consider a modified version of the example I showed yesterday: type Rec1 is record A : aliased Integer; C : Character; end record; for Rec1 use record A at 0 range 0 .. 31; C at 4 range 0 .. 7; end record; type Rec2 is new Rec1; for Rec2 use record A at 4 range 0 .. 31; C at 0 range 0 .. 7; end record; procedure Bar (P : access constant Integer); R1 : Rec1; type CAccInt is access constant Integer; P1 : CAccInt; P1 := Rec2(R1).A'Access; -- (1) Bar (Rec2(R1).A'Access); procedure Bar (P : access constant Integer) is begin P1 := P; -- (2) end Bar; One hopes that (1) is illegal and (2) raises Program_Error, as in both cases the access value far outlives the (temporary) object that it designates. That's because the type conversion Rec2(R1) has to make a copy of the object in order to change the representation. We haven't been able to find any rules that make this the case (the rules all talk about function calls and aggregates, but value conversions have the same issues). We can also construct similar examples using unrelated array types (for which there is no possibility of banning representation changes). Also note that there is an entire (short) clause in the Standard about the wonders of type conversions like the above (13.6). So it seems pretty clear that such a conversion is intended to be allowed. As such, it needs accessibility. Steve (in his typically Bairdian way) has managed to worry about controlled components in such a conversion; presuming the accessibility of the conversion is properly defined, the components will get appropriate lifetimes. So that's not a real problem (although it might be enough of an implementation headache to want to ban it). Steve would like to go further and ban any type conversions that change representations for by-reference types, using as his argument 6.2(10/3). That may or may not be a good idea (I'll leave it to Steve to argue that), but I don't find it important because the underlying problem remains unless *all* representation changing conversions of composite types are banned (or "aliased" is made by-reference), and both of those solutions would be a massive incompatibility. **************************************************************** From: Tucker Taft Sent: Wednesday, July 18, 2012 3:11 PM > We all agree (I hope) that some type conversions involve copying. The > problem is that the accessibility rules don't, so far as I can tell, > take this copying into account. This is irrespective of whether > by-reference types can be copied or not, as aliased components don't > make a type by-reference. (Perhaps they should have, but it is way too > late for that sort of change, as it would have severe compatibility effects.) ... I agree that a value conversion should be treated like a function return in general, as far as the accessibility levels of the aliased subcomponents and access discriminants. This doesn't seem very controversial to me... I still am curious about the by-ref value conversions, however! **************************************************************** From: Randy Brukardt Sent: Wednesday, July 18, 2012 3:54 PM > This doesn't seem very controversial to me... It's not that controversial, just a pain in the wording and possibly implementation. > I still am curious about the by-ref value conversions, however! Steve is preparing something on that, I think. I personally think that 6.2(10/3) is bogus in the case of value conversions; it is written as if only view conversions can be passed as parameters, but that is clearly not true for "in" parameters. Fixing that along with properly defining the accessibility of value conversions would fix all known problems. But there are other options, which I will let Steve outline. **************************************************************** From: Steve Baird Sent: Wednesday, July 18, 2012 5:07 PM > I still am curious about the by-ref value conversions, however! 6.2(10/3) says: Each value of a by-reference type has an associated object. For a ... type_conversion, this object is the one associated with the operand. I think there was no oversight there; the above wording is just what was intended. The case where a conversion would have to make a copy of an object of a by-reference type was supposed to be prevented by 13.1(10/3): For an untagged derived type, it is illegal to specify a type-related representation aspect if the parent type is a by-reference type, or has any user-defined primitive subprograms. Unfortunately, we encountered an obscure case where such a copy-requiring type conversion is allowed. 4.6(24.9/2).says The operand type of a view conversion shall not have a tagged, private, or volatile subcomponent. Some background here: 1) Because we are talking about static semantics here, we have to conservatively talk about whether a type *might* be a by-reference type (which is what this wording accomplishes), as opposed to whether it definitely *is* a by-reference type. (there was also a secondary discussion about how 13.1(10/3), quoted above, gets this point wrong - that is a separate problem). 2) This is a rule about the legality of "structural" array type conversions - conversions between array types that are unrelated by derivation. This rule has nothing to do with "normal" type conversions. So this rule, roughly speaking, bans view conversions between by-reference array types that are unrelated by derivation. The problem is that it doesn't go far enough. It says nothing about value conversions. Randy and I concluded that this ban should not be restricted to view conversions. I suggested this paragraph should be replaced with The operand type shall not have a tagged, private, or volatile subcomponent. This would strengthen the ban to include value conversions. This would be an incompatible change. It would ban some conversions which were previously legal (albeit with unclear dynamic semantics, at least in some cases). **************************************************************** From: Tucker Taft Sent: Wednesday, July 18, 2012 5:21 PM > 6.2(10/3) says: > Each value of a by-reference type has an associated object. > For a ... type_conversion, this object is the one associated with the > operand. ... Why not change this to say "for a view conversion"? Then for a value conversion, we could get a new object. Or say "for a type conversion between types with a common ancestor", and get a new object for other conversions. **************************************************************** From: Randy Brukardt Sent: Wednesday, July 18, 2012 5:37 PM ... > 6.2(10/3) says: > Each value of a by-reference type has an associated object. > For a ... type_conversion, this object is the one associated > with the operand. > > I think there was no oversight there; the above wording is just what > was intended. The case where a conversion would have to make a copy of > an object of a by-reference type was supposed to be prevented by > 13.1(10/3): > > For an untagged derived type, it is illegal to specify a > type-related representation aspect if the parent type is > a by-reference type, or has any user-defined primitive subprograms. The problem here is that you are assuming a conclusion and justifying it. Tucker asked to see both sides... > Unfortunately, we encountered an obscure case where such a > copy-requiring type conversion is allowed. 4.6(24.9/2).says > > The operand type of a view conversion shall not have a tagged, > private, or volatile subcomponent. Steve didn't provide an example here, so let me do it: type T is tagged ... type A1 is array (1 .. 10) of T; for A1'Component_Size use 48; -- Assume this is OK for this type. type A2 is array (1 .. 10) of T; for A2'Component_Size use 64; -- Assume this is OK for this type. Var : A1; procedure P1 (Obj : in out A2); procedure P2 (Obj : in A2); P1 (A2(Var)); -- Illegal by 4.6(24.9/2) P2 (A2(Var)); -- Currently OK, must make a copy of the operand. The wording of rules 4.6(24.8/2) and 4.6(24.9/2), which only apply to view conversions, imply that the expectation was that even by-reference objects can be copied in a *value* conversion. If that is not true, then clearly both of these rules should apply to all conversions, not just view conversions. (I also worry that there are other rules with similar problems, but I have not done any extensive looking for that.) ... > The problem is that it doesn't go far enough. It says nothing about > value conversions. You again are assuming the conclusion. There is almost equal evidence in the Standard for and against this proposition, and we ought to not leap to conclusions. > Randy and I concluded that this ban should not be restricted to view > conversions. I suggested this paragraph should be replaced with > > The operand type shall not have a tagged, > private, or volatile subcomponent. Note that I did so totally for implementation reasons. Having to treat a type conversion as a local master (with the finalization implications) seems like a pain in the neck, and we might want a build-in-place analog as well so such finalization was not required. Banning them is easier than going through that. But there is no *semantic* problem with allowing them, presuming that the accessibility of type conversions is properly defined (as noted in my previous mail). Once one makes this decision, it is unnecessary to decide whether by-reference is never copied or not. Which is better than arguing it, because I strongly believe that it should be OK to copy non-limited by-reference types in value conversions and the like. (Janus/Ada 83 depended very heavily on this in our generic sharing implementation -- almost all parameters were passed by-copy. Not so much in Ada 95.) ... > This would be an incompatible change. It would ban some conversions > which were previously legal (albeit with unclear dynamic semantics, at > least in some cases). It would ban conversions with just fine dynamic semantics: Var2 : A2; Var2 := A2 (Var); -- Illegal by proposed rule. Type conversions aren't just used to pass parameters!! I think the reason to tolerate the incompatibility is because of the mess that controlled components would make. I don't see any strong reason beyond that to ban this (I'd rather repeal 13.1(10/3), which is a pain in the neck as it prevents most useful uses of derivation of untagged types - but let's leave that for another day). **************************************************************** From: Randy Brukardt Sent: Wednesday, July 18, 2012 5:39 PM ... > > 6.2(10/3) says: > > Each value of a by-reference type has an associated object. > > For a ... type_conversion, this object is the one associated with > > the operand. ... > > Why not change this to say "for a view conversion"? > Then for a value conversion, we could get a new object. > > Or say "for a type conversion between types with a common ancestor", > and get a new object for other conversions. Steve has no adequate answer for that, because there is none. ;-) The important problem is the one Steve ignored: finalization of controlled components in copied value type conversions could be a mess. (Controlled always makes a type by-reference.) If they are *not* a mess, I throughly agree with you. **************************************************************** From: Steve Baird Sent: Thursday, July 19, 2012 1:10 AM > Steve has no adequate answer for that, because there is none. ;-) Well, I agree that these are appealing approaches given that we have to worry about compatibility. I'd argue more strongly for the simpler tighten-up-the-legality-rule solution that I mentioned earlier if we didn't have to worry about compatibility, but we do. > The important problem is the one Steve ignored: finalization of > controlled components in copied value type conversions could be a > mess. (Controlled always makes a type by-reference.) If they are *not* > a mess, I throughly agree with you. But, as Randy points out, Tuck's proposed changes don't completely solve the problem. Making a copy requires some new wording to handle the case where controlled parts are copied. Implementing this case would also have a poor implementation-effort-to-user-utility ratio. Randy says he would like the solutions Tuck suggests if the interactions with controlled types are not messy; I suppose I agree with that, but I think those interactions are messy. Tuck - do you want to consider a an approach where the copy is not adjusted and finalized? Maybe this could be made to work, but the thought makes me nervous. Using controlled types to implement reference counting is complicated enough without introducing something like this. Tucker Taft wrote: > I agree that a value conversion should be treated like a function > return in general If you want to follow the function/aggregate model (which I agree is the cleanest model if we are going to make a copy), then this would suggest that the copy is adjusted and finalized, There is also a dynamic-semantics compatibility concern (which, of course, is in some sense more serious than the statically-detectable incompatibility associated with tightening up a legality rule). If we change the rules about when a copy is generated for a type conversion, then this could be an incompatible change in the dynamic semantics of an existing non-erroneous program. Such a change would rarely make a difference in practice, but debugging the consequences if it did make a difference could be painful. **************************************************************** From: Randy Brukardt Sent: Thursday, July 19, 2012 2:02 AM ... > But, as Randy points out, Tuck's proposed changes don't completely > solve the problem. Making a copy requires some new wording to handle > the case where controlled parts are copied. > Implementing this case would also have a poor > implementation-effort-to-user-utility ratio. > Randy says he would like the solutions Tuck suggests if the > interactions with controlled types are not messy; I suppose I agree > with that, but I think those interactions are messy. > Tuck - do you want to consider a an approach where the copy is not > adjusted and finalized? Maybe this could be made to work, but the > thought makes me nervous. Using controlled types to implement > reference counting is complicated enough without introducing something > like this. That would be a disaster. There can be no such places in the language. (We went through removing such misguided permissions from Ada 95, let's not put any back!) > Tucker Taft wrote: > > I agree that a value conversion should be treated like a function > > return in general > > If you want to follow the function/aggregate model (which I agree is > the cleanest model if we are going to make a copy), then this would > suggest that the copy is adjusted and finalized, Yes, it has to be. > There is also a dynamic-semantics compatibility concern (which, of > course, is in some sense more serious than the statically-detectable > incompatibility associated with tightening up a legality rule). > If we change the rules about when a copy is generated for a type > conversion, then this could be an incompatible change in the dynamic > semantics of an existing non-erroneous program. > Such a change would rarely make a difference in practice, but > debugging the consequences if it did make a difference could be > painful. There has to be a build-in-place permission here, just as there is for functions and aggregates. (We surely don't want to force copies if they aren't needed.) With that permission, there is no need for adjusting/finalizing unless an actual copy is made by the type conversion. And if a copy is made, and no adjust/finalize is going on, the code is already broken (it would destroy Claw, for example) and I don't really care about a dynamic "incompatibility" (the "incompatibility" probably would fix as many bugs as it caused). So I think this would work. My big concern is about the cost of implementing such a mechanism for rare cases, but perhaps that's not a significant concern (the mechanism being the same as used for aggregates in similar locations in the code). **************************************************************** From: Tucker Taft Sent: Thursday, July 19, 2012 8:22 AM > If you want to follow the function/aggregate model (which I agree is > the cleanest model if we are going to make a copy), then this would > suggest that the copy is adjusted and finalized, Absolutely, if a copy is actually performed. I am not proposing we *require* a copy, but rather, we allow a value conversion between two arrays with different representations, even if one of the components might be by-reference. > There is also a dynamic-semantics compatibility concern (which, of > course, is in some sense more serious than the statically-detectable > incompatibility associated with tightening up a legality rule). > If we change the rules about when a copy is generated for a type > conversion, then this could be an incompatible change in the dynamic > semantics of an existing non-erroneous program. Such a change would > rarely make a difference in practice, but debugging the consequences > if it did make a difference could be painful. I certainly don't want to require a copy if it is not needed, so I don't see the issue here. **************************************************************** From: Steve Baird Sent: Thursday, July 19, 2012 11:12 AM > There has to be a build-in-place permission here, just as there is for > functions and aggregates. (We surely don't want to force copies if > they aren't needed.) With that permission, there is no need for > adjusting/finalizing unless an actual copy is made by the type conversion. > And if a copy is made, and no adjust/finalize is going on, the code is > already broken (it would destroy Claw, for example) and I don't really > care about a dynamic "incompatibility" (the "incompatibility" probably > would fix as many bugs as it caused). I agree that if we don't want to accept the incompatibility of tightening up the legality rule, then allowing, as opposed to requiring, a copy is probably the way to go. In 3.10.2, would the (dynamic) accessibility level of the conversion result depend on whether a copy was made? What about static accessibility checking? type Ref is access constant Element; Ptr : Ref; type A1 is array (...) of aliased Element with Component_Size => Xxx; type A2 is array (...) of aliased Element with Component_Size => Yyy; --- Xxx /= Yyy X1 : A1 (...); procedure Foo is begin -- Ptr := A2 (X1) (23)'Access; -- legal? end Foo; Perhaps for purposes of static accessibility checking, we could make a conservative assumption (and therefore unconditionally reject the above example). Similarly, would the definition of "associated object" depend on this choice? Dealing with these complications may well be worth it in order to avoid the incompatibility problem, but they would need to be dealt with. It sure would be simpler to just delete a few words in one paragraph, plug the legality hole, and implement the original intent of the language designers. However, I appreciate that we should be willing to go to some trouble to avoid introducing an incompatibility. It would be interesting to know the impact of the incompatibility we are trying to avoid. How often to folks really convert between unrelated-by-derivation might-be-by-reference array types? > So I think this would work. My big concern is about the cost of > implementing such a mechanism for rare cases, but perhaps that's not a > significant concern (the mechanism being the same as used for > aggregates in similar locations in the code). Agreed (on all points). **************************************************************** From: Tucker Taft Sent: Thursday, July 19, 2012 11:35 AM > In 3.10.2, would the (dynamic) accessibility level of the conversion > result depend on whether a copy was made? No. It would only depend on whether the types have a common ancestor, and the conversion is a "value" conversion. > What about static accessibility checking? No. > type Ref is access constant Element; > Ptr : Ref; > > type A1 is array (...) of aliased Element with Component_Size => Xxx; > type A2 is array (...) of aliased Element with Component_Size => Yyy; > --- Xxx /= Yyy > > X1 : A1 (...); > > procedure Foo is > begin -- > Ptr := A2 (X1) (23)'Access; -- legal? No. > end Foo; > > Perhaps for purposes of static accessibility checking, we could make a > conservative assumption (and therefore unconditionally reject the > above example). Yes. > > Similarly, would the definition of "associated object" depend on this > choice? No, it would always be the newly created object (even if it happens to reside in the same place as the old object). > Dealing with these complications may well be worth it in order to > avoid the incompatibility problem, but they would need to be dealt with. > > It sure would be simpler to just delete a few words in one paragraph, > plug the legality hole, and implement the original intent of the > language designers. However, I appreciate that we should be willing to > go to some trouble to avoid introducing an incompatibility. > > It would be interesting to know the impact of the incompatibility we > are trying to avoid. How often to folks really convert between > unrelated-by-derivation might-be-by-reference array types? Based on your might-be-by-reference, that includes any array type with private subcomponents. That puts a pretty harsh effect on using private types. >> So I think this would work. My big concern is about the cost of >> implementing such a mechanism for rare cases, but perhaps that's not >> a significant concern (the mechanism being the same as used for >> aggregates in similar locations in the code). > > Agreed (on all points). I really don't see this as a major burden, since temps are created in many circumstances, and I presume the mechanism for creating a temp is smart enough to deal with temps that need finalization. **************************************************************** From: Steve Baird Sent: Thursday, July 19, 2012 12:19 PM > No. ... > No. > No. Sounds right. The idea is that a copy is created unconditionally for one of these conversions; the only thing that is implementation dependent is whether the "copy" is built-in-place on top of the operand of the type conversion. This is a novel use for build-in-place, but I don't see any obvious problems with it. > Based on your might-be-by-reference, that includes any array type with > private subcomponents. That puts a pretty harsh effect on using > private types. I suspect that "structural" array conversions between array types with non-scalar element types are uncommon to begin with. However, I don't have supporting data for this. If I am correct about this, then the legality rule change we've been discussing would have the effect of disallowing some subset of an unimportant corner case and I wouldn't call that "a harsh effect". **************************************************************** From: Jean-Pierre Rosen Sent: Friday, July 20, 2012 1:23 AM > I suspect that "structural" array conversions between array types with > non-scalar element types are uncommon to begin with. However, I don't > have supporting data for this. I think the same - because most people are not aware of that possibility. I don't even talk about it in my course. Hmmm... I could add a check in AdaControl for this case, and run it on clients code I have here. I'll report the result here, but don't hold your breath (I'm off the Internet all of next week). **************************************************************** From: Brad Moore Sent: Friday, July 20, 2012 7:56 AM > It would be interesting to know the impact of the incompatibility we > are trying to avoid. How often to folks really convert between > unrelated-by-derivation might-be-by-reference array types? I suppose one of the most likely cases for this would be where one wants one type that is compact for minimal storage in an embedded device where persistent storage space is highly constrained, and where a non-packed type is used for computation purposes. I recall seeing such usages, though the arrays in this case weren't might-be-by-reference array types, as this code was originally written for Ada 83, which didn't support aliased components. That would of course further reduce the likelihood of usage, as I doubt any such array types would have been introduced when the code was ported to Ada 2005. **************************************************************** From: Steve Baird Sent: Friday, July 20, 2012 12:41 PM > I suppose one of the most likely cases for this would be where one > wants one type that is compact for minimal storage in an embedded > device where persistent storage space is highly constrained, and where > a non-packed type is used for computation purposes. In cases like this, the two array types are usually related by derivation. Typically one of them is derived from the other, but at least they have a common ancestor. The legality change we have been discussing would have no effect in this case; it could only make a difference if the two array types have no common ancestor. **************************************************************** From: Randy Brukardt Sent: Friday, July 20, 2012 1:07 PM > The legality change we have been discussing would have no effect in > this case; it could only make a difference if the two array types have > no common ancestor. That would be the case if 13.1(10/3) did not exist, but since it does, it's almost impossible to have two derived types with different representations in practice. (Having no primitive operations is highly unlikely unless you go out of your way to create an insane program architecture.) And since you can interconvert the arrays whether or not they are related, there is no need for them to be related by derivation. In addition, there are lots of anonymous array types out there (which you can convert from, not to). So I would not jump to conclusions here. I suspect that such conversions are rare, but that's mainly because value conversions (and indeed copying) are rare for non-scalar types. The better question is whether its worth the baggage to disallow perfectly good conversions simply because you don't want to bother to implement them. We need to define the accessibility and build-in-place rules in any case (they can matter in the non-by-reference conversion case, which no one is suggesting to ban). So definitionally, there is no extra work here. (Aside: I just saw a case where such an implementation-oriented restriction has bitten someone; I've asked them to submit their example to Ada-Comment but I don't know if they actually will do so. As always, the rule ought to be to minimize such restrictions.) **************************************************************** From: Steve Baird Sent: Friday, July 20, 2012 1:29 PM > That would be the case if 13.1(10/3) did not exist, but since it does, > it's almost impossible to have two derived types with different > representations in practice. (Having no primitive operations is highly > unlikely unless you go out of your way to create an insane program > architecture.) I disagree, but I also think this is just a conflict of opinions unsupported by data. An array type may often be declared without any user-defined primitive ops, particularly if it is used as a component type or a designated type in the context of declaring some other type that does have interesting operations. **************************************************************** From: Tucker Taft Sent: Friday, July 20, 2012 1:39 PM > ... An array type may often be declared without any user-defined > primitive ops, particularly if it is used as a component type or a > designated type in the context of declaring some other type that does > have interesting operations. But if you go to the trouble of declaring *two* array types, one packed, and one not, it seems pretty likely that at least one of them is going to have some operations. Furthermore, it is annoying to suddenly run into this limitation when during maintenance you decide it would be appropriate to add an operation on one or the other. But as you say, we don't really have data here. **************************************************************** From: Randy Brukardt Sent: Friday, July 20, 2012 1:54 PM > > ... An array type may often be declared without any user-defined > > primitive ops, particularly if it is used as a component type or a > > designated type in the context of declaring some other type that > > does have interesting operations. > > But if you go to the trouble of declaring *two* array types, one > packed, and one not, it seems pretty likely that at least one of them > is going to have some operations. The use case that you (Steve) postulated was a packed array for storage and a faster unpacked array for processing. Exactly how is that processing going to happen without operations? Osmosis?? > Furthermore, it is annoying to suddenly run into this limitation when > during maintenance you decide it would be appropriate to add an > operation on one or the other. > > But as you say, we don't really have data here. Right. In the absence of good data, I would tend to err on the conservative side: don't introduce an incompatibility and bite the bullet on the work needed (which probably can be ignored until/unless a bug report appears). **************************************************************** From: Tucker Taft Sent: Friday, July 20, 2012 2:18 PM I don't consider this "new work." If this was legal before, it clearly required a copy, since the representation was different. I presume that a copy implies a temp, and a temp implies the possibility of finalization. Of course it might not have been implemented before at all, in which case it is probably OK to leave it unimplemented now as well... ;-) **************************************************************** From: Steve Baird Sent: Friday, July 20, 2012 2:28 PM > Right. In the absence of good data, I would tend to err on the conservative > side: don't introduce an incompatibility and bite the bullet on the > work needed (which probably can be ignored until/unless a bug report appears). You are probably right. A FUD argument cannot be ignored when we are talking about an incompatibility. **************************************************************** From: Jean-Pierre Rosen Sent: Friday, July 27, 2012 4:30 AM > I suspect that "structural" array conversions between array types with > non-scalar element types are uncommon to begin with. However, I don't > have supporting data for this. Well, I just had some (unexpected) free time, so I added the rule to AdaControl and checked on some sample code from my clients (no names of course ;-) ). - Client 1: 2 big air traffic applications. App1: 3218 comp units, 26 structural array conversions. App2: 5553 comp units, 39 structural array conversions - Client 2: Railway application. 228 comp units, 26 structural array conversions (located in 5 units). - Client3: Competitor Railway application. 315 comp units, no structural array conversions. I sampled some conversions; from what I've seen, they seem to be caused by incorrect typing (same type defined in two different packages), or by the use of 'Image/'Value with custom defined string types. The only ones I saw whose components were not scalars were arrays of Unbounded_Wide_String. **************************************************************** From: Steve Baird Sent: Friday, November 30, 2012 7:07 PM > Thanks to Randy for much useful discussion on this one. [Followed by new !wording and !discussion sections, in version /03 of the AI; most of the submitted !discussion was placed in the !question. - Editor.] **************************************************************** From: Tucker Taft Sent: Saturday, December 1, 2012 10:15 AM > We don't want access values pointing to unaliased objects. I prefer your solution #2, and just require copying when aliased-ness disagrees. **************************************************************** From: Steve Baird Sent: Saturday, December 8, 2012 2:09 AM proposed AI12-0027 wording: [Followed by a new !wording section, in version /04 of the AI - Editor.] **************************************************************** From: Tucker Taft Sent: Saturday, December 8, 2012 6:59 AM ... > Append at the end of Dynamic Semantics section of 4.6: > > Evaluation of a value conversion of a composite type will either > create a new anonymous object [(similar to the object > created by the evaluation of an aggregate or a function call)] or > yield a new view of the operand object without creating > a new object: > > - If the target type is a by-reference type and there is a > type that is an ancestor of both the target type and the > operand type then a new object shall not be created. No "shall" in dynamic semantics. > > - If the target type is an array type having aliased components and > the operand type is an array type having unaliased components, > then a new object shall be created. Lose the "shall" > > - Otherwise, it is unspecified whether a new object is created. > > If a new object is created, then the initialization of that object is > an assignment operation. > > AARM note: This makes a difference in the case of converting from > an array type with unaliased components to one with aliased components > if the element type has a controlled part. > > > Append after 3.10.2(10/3): > > The accessibility of a value conversion (see 4.6) is defined as for an > aggregate. ... This still makes me nervous. We need to look at all places "aggregate" appears in 3.10.2. **************************************************************** From: Randy Brukardt Sent: Monday, December 31, 2012 7:44 PM [Please don't stop reading just because I mentioned "accessibility"!!] AI12-0027-1 says to modify 3.10.2(10/3): The accessibility level of an aggregate that is used (in its entirety) to directly initialize part of an object is that of the object being initialized. In other contexts, the accessibility level of an aggregate is that of the innermost master that evaluates the aggregate. {Corresponding rules apply to a value conversion (see 4.6).} I have to document this as a possible incompatibility, as the accessibility in this case was not previously defined. If a compiler used the accessibility of the operand type (which would make sense for by-reference types, especially as accessibility is defined this way for view conversions), this will change the lifetime to be very short and thus most likely make the code illegal. (Of course, such code should be pretty rare ['Access of a component of a type conversion], and would most likely have created a dangling pointer if a copy actually was made.) The reason for this rule is that the value conversion *might* make a copy, and we don't want Legality Rules to depend on whether the implementation chooses to make a copy or not. So far so good. But what about the case where the implementation is not allowed to make a copy? It seems weird to insist that the implementation *not* make a copy and at the same time treat the conversion as if it *did* make a copy for accessibility purposes. Moreover, the most likely cases involve by-reference types and parameter passing and thus probably will not be allowed to make a copy. So, I'm wondering if we should be excepting value conversions that are required to not make a copy. This would look something like: {Corresponding rules apply to a value conversion (see 4.6), unless the value conversion is not allowed to make a new object, in which case the accessibility level is the same as the operand.} This would reduce (but not completely eliminate) the possible incompatibility, and more closely match the intuition (and view conversions). OTOH, it is more complicated, and we don't change the accessibility for build-in-place objects in similar circumstances (which I find weird, but whatever). Any thoughts?? **************************************************************** From: Jeff Cousins Sent: Tuesday, January 8, 2013 10:05 AM On the basis that first reactions are often right, I'd go with your suggested change, since both a reduced incompatibility and more "intuitive" (not that much to do with accessibility is intuitive). **************************************************************** From: Tucker Taft Sent: Tuesday, January 8, 2013 12:58 PM > This would reduce (but not completely eliminate) the possible > incompatibility, and more closely match the intuition (and view > conversions). OTOH, it is more complicated, and we don't change the > accessibility for build-in-place objects in similar circumstances > (which I find weird, but whatever). Can you give a couple of simple examples to justify the added complexity? I have trouble buying any "match the intuition" argument when talking about accessibility. ;-) **************************************************************** From: Steve Baird Sent: Tuesday, January 8, 2013 1:36 PM > > AI12-0027-1 says to modify 3.10.2(10/3): > > The accessibility level of an aggregate that is used (in its entirety) > to directly initialize part of an object is that of the object being > initialized. In other contexts, the accessibility level of an > aggregate is that of the innermost master that evaluates the > aggregate. {Corresponding rules apply to a value conversion (see > 4.6).} > ... > So, I'm wondering if we should be excepting value conversions that are > required to not make a copy. This would look something like: > > {Corresponding rules apply to a value conversion (see 4.6), unless the > value conversion is not allowed to make a new object, in which case > the accessibility level is the same as the operand.} Wouldn't this mix static and dynamic semantics in a privacy-breaking way? As you point out, this rule could impact the legality of certain (obscure) uses of 'Access. Therefore we are certainly talking about static semantics here. However, the "unless the value conversion is not allowed to make a new object" wording presumably refers to the new (added in AI12-0027) wording in the dynamic semantics section of 4.6. In particular, consider a value conversion involving a private type which might or might not be completed as a by-reference type. Perhaps you could define some rule which would somehow make conservative assumptions about private types, but this wouldn't just fall out from the proposed wording. > This would reduce (but not completely eliminate) the possible > incompatibility, and more closely match the intuition (and view > conversions). OTOH, it is more complicated, and we don't change the > accessibility for build-in-place objects in similar circumstances > (which I find weird, but whatever). > > Any thoughts?? I claim that if we want to do anything at all here, we need at least a somewhat more complicated solution than what you proposed. It seems like this strengthens the argument for doing nothing. **************************************************************** From: Randy Brukardt Sent: Tuesday, January 8, 2013 2:26 PM > However, the "unless the value conversion is not allowed to make a new > object" wording presumably refers to the new (added in AI12-0027) > wording in the dynamic semantics section of 4.6. In particular, > consider a value conversion involving a private type which might or > might not be completed as a by-reference type. Ugh. I think you're right. > Perhaps you could define some rule which would somehow make > conservative assumptions about private types, but this wouldn't just > fall out from the proposed wording. > > > This would reduce (but not completely eliminate) the possible > > incompatibility, and more closely match the intuition (and view > > conversions). OTOH, it is more complicated, and we don't change the > > accessibility for build-in-place objects in similar circumstances > > (which I find weird, but whatever). > > > > Any thoughts?? > > I claim that if we want to do anything at all here, we need at least a > somewhat more complicated solution than what you proposed. It seems > like this strengthens the argument for doing nothing. You're probably right. It also explains the reason that we don't do this for build-in-place, since they too might depend on dynamic semantics. One could use "immutably limited or tagged" to get around this: {Corresponding rules apply to a value conversion (see 4.6), unless the target type of the value conversion has a tagged or immutably limited part, in which case the accessibility level is the same as the operand.} AARM Note: This is a static semantics rule, so we only consider parts that are visible (we don't look into private parts to determine if any parts are involved). I think we may need to consider this (see my response to Tucker). **************************************************************** From: Randy Brukardt Sent: Tuesday, January 8, 2013 2:55 PM > Can you give a couple of simple examples to justify the added > complexity? > I have trouble buying any "match the intuition" argument when talking > about accessibility. ;-) Let me just give one. Not all accessibility checks are associated with 'Access, and I think the one associated with "aliased" parameters will be relatively common. Consider: generic type Elem is private; package P is package Vect is new Ada.Containers.Vectors (Elem, Natural); type Holder is record V : Vect.Vector; F : aliased Float; ... end record; function Constant_Reference (H : aliased in Holder; I : in Natural) return Vect.Constant_Reference_Type; -- Give direct reading access to the elements of H.V. end P; with P; package Q is package My_P is new P (Float); type My_Holder is new My_P.Holder; -- A Tucker derivation. Q_Hold : My_Holder; Ptr : access Float; ... end Q; with Q; procedure Main is begin -- Use explicit conversion: Q.Ptr := new Float'(Q.My_P.Constant_Reference(Q.My_P(Q.Q_Hold), I).all); -- Fails accessibility. -- Use inherited version (which uses an implicit conversion identical to the item above) Q.Ptr := new Float'(Q.Constant_Reference(Q.Q_Hold, I).all); -- ??? -- Q.Ptr := Q.My_P(Q.Q_Hold).F'access; -- Fails accessibility. end Main; Without the change I'm suggesting, the first call fails the accessibility check for an aliased parameter. (It has to live as long as the return object, but here it is very short lived, while the return object might have library-level accessibility.) I'm not sure if the second call fails the same check, but it seems like it ought to (the conversion being implicit or explicit doesn't matter). The intuition for these calls is that Q.Q_Hold is library-level, so it lives long enough for the allocator, and there shouldn't be a problem. But there IS a problem, simply because of the value conversion, and moreover it cannot be worked around (the conversion is there no matter how you write the call). The last case is a similar example using 'Access rather than Constant_Reference (but I think this is unlikely enough to not worry about). And this case can be worked around (we don't have to write the conversion here). [I originally used Constant_Reference here because I thought the problem was more wide-spread, but I've convinced myself that it only can happen in an allocator as there is a special rule for the accessibility of actual parameters of aliased formal parameters.] We can at least reduce the incompatibility (which I agree is minor) by adopting the rule I suggested in my reply to Steve. But as that cannot cover private types, it's not clear that it is worth it. **************************************************************** From: Tucker Taft Sent: Tuesday, January 8, 2013 3:22 PM > Q.Ptr := new > Float'(Q.My_P.Constant_Reference(Q.My_P(Q.Q_Hold), > I).all); -- Fails accessibility. I think this should be: Q.Ptr := new Float'(Q.My_P.Constant_Reference(Q.My_P.Holder(Q.Q_Hold), I).all); But Holders are tagged, and all conversions of tagged types are view conversions. So I don't see this issue. As far as immutably limited, an alternative approach would be to say that all conversions of immutably-limited types are view conversions. That seems to be where we are headed... **************************************************************** From: Randy Brukardt Sent: Tuesday, January 8, 2013 4:18 PM ... > > type Holder is record > > V : Vect.Vector; > > F : aliased Float; > > ... > > end record; ... > > with Q; > > procedure Main is > > begin > > -- Use explicit conversion: > > Q.Ptr := new > > Float'(Q.My_P.Constant_Reference(Q.My_P(Q.Q_Hold), I).all); -- Fails accessibility. > > I think this should be: > > Q.Ptr := new Float'(Q.My_P.Constant_Reference(Q.My_P.Holder(Q.Q_Hold), I).all); > > But Holders are tagged, and all conversions of tagged types are view > conversions. So I don't see this issue. Huh? Holder is an untagged record type that I declared (see quoted text above). Probably I should have called it "Bar" or "Frob" just to avoid confusion. But it certainly is not a tagged type (it has a *part* of a tagged type). > As far as immutably limited, an alternative approach would be to say > that all conversions of immutably-limited types are view conversions. > That seems to be where we are headed... That's not necessarily a bad idea, as it mimics the rule for tagged types. They're always by-reference, so why not treat them that way? It doesn't help examples like the one above (these have "parts" that are tagged or immutably limited), but it would reduce the incompatibility a bit more and it's pretty hard to create these examples in any case (this example was a lot harder to write than I expected at the start). ****************************************************************