!standard 7.6.1(6) 09-05-30 AI05-0099-1/04 !standard 7.6.1(7) !standard 7.6.1(8) !standard 7.6.1(9/2) !class binding interpretation 08-05-28 !status Amendment 201Z 08-11-26 !status ARG Approved 8-0-1 08-10-31 !status work item 08-05-28 !status received 06-04-09 !priority Medium !difficulty Medium !qualifier Omission !subject The tag, not the type, of an object determines if it is controlled !summary The finalization actions for an object are determined by the runtime type of an object (as identified by the tag, if any, of the object) and not by the nominal subtype of the object. !question When an object is finalized, 7.6.1(7) says, "If the object is of a controlled type, the Finalize procedure is called". If the phrase "The object is of type Z" is equivalent to "The object's nominal subtype is Z" for objects declared by an object_declaration, as 3.3.1(8) would seem to imply, then there's a problem if T is an interface type: Obj : Int'Class := ; because the "specific type identified by the tag" (this is the phrase used in other places in the RM) may be a controlled or a non-controlled type; thus, when Obj is finalized, it can't be determined statically whether any Finalize routine needs to be called. But Finalize definitely needs to be called if the specific type is controlled, right? (Yes.) !wording Modify 7.6.1(6): * If {the full type of} the object is [of] an elementary type, finalization has no effect; Replace 7.6.1(7) by: * If the full type of the object is a tagged type, and the tag of the object identifies a controlled type, the Finalize procedure of that controlled type is called; Modify 7.6.1(8): * If {the full type of} the object is [of] a protected type, {or if the full type of the object is a tagged type and the tag of the object identifies a protected type, }the actions defined in 9.4 are performed; Modify the start of 7.6.1(9/2): * If {the full type of} the object is [of] a composite type, then after performing the above actions... Add an AARM note after 7.6.1(9.a): To Be Honest: The components discussed here are all of the components that the object actually has, not just those components that are statically identified by the type of the object. These can be different if the object has a classwide type. !discussion The rule in question is a dynamic semantics rule, so depending on a static concept like "nominal subtype" is suspicious. However, there is no clear definition of the "dynamic type" of an object in the Standard. Since T'Class can include an object of any descendant of T, we surely do not want to be calling the Finalize (if any) that is statically associated with T. In similar cases in the Standard, we have wording specifically to handle class-wide cases. For instance, membership operations specifically mention testing the tag (4.5.2(30.1/2)). Type conversions also mention testing the tag (4.6(42)). There doesn't seem to be other places where this problem occurs, so it doesn't seem necessary to define a new term like "dynamic type"; we can just fix this occurrence. This wording was OK (although vague) for Ada 95, as any class-wide type that could have controlled specific types would necessarily be controlled. But that is not true in Ada 2005 because of interfaces. The original wording is vague as to which type's Finalize is called, especially for class-wide types. We might as well eliminate this vagueness as well. This is why we do not try to follow the lead of other similar wording and talk only about class-wide types - we need to say which type's Finalize is called in every case. The new wording makes it crystal clear which Finalize routine is called (the one belonging to the specific type identified by the tag of the object - it never has anything to do with the nominal subtype). Finally, the new wording also eliminates any confusion about whether privacy has any bearing on finalization (it does not). We add the "full type" wording to all of the bullets here to be consistent. 7.6.1(8) has a similar problem for a (tagged) protected type that inherits from a limited or synchronized interface. Thus we reword it as well. Note that 7.6.1(9) does not need a correction, as all tagged types are composite, and thus the use of classwide types does not change this property. We add a "To Be Honest" AARM note to make it clear that we are talking about the components that the object actually has, not necessarily those that are identified statically by the type. !corrigendum 7.6.1(6) @drepl @xbullet @dby @xbullet !corrigendum 7.6.1(7) @drepl @xbullet @dby @xbullet !corrigendum 7.6.1(8) @drepl @xbullet @dby @xbullet !corrigendum 7.6.1(9/2) @drepl @xbullets;> @dby @xbullets;> !ACATS Test We do not expect that this will change the semantics of any Ada program, so no test should be needed. There might be value to a C-Test that checks that controlled types that inherit from interfaces get finalized properly. !appendix !topic What does "object of type T" mean when nominal type is classwide? !reference RM05 3.3.1(8), 7.6.1(7) !from Adam Beneschan 08-04-09 !discussion This is one of those nitpicky cases where I have a feeling there's no doubt about what's supposed to happen but the RM wording may be technically ambiguous or incorrect. 3.3.1(8) says, "The object_declaration declares an object of the type of the nominal subtype". So in this case: Obj : T'Class := ; Is the type of the object T'Class, or is it the specific type given by the type of the expression? Or does this depend on whether we're talking about the object itself or the view of the object? The reason I'm asking is because I'm trying to figure out just what 7.6.1(7) means for objects like this; when an object is finalized, this clause says, "If the object is of a controlled type, the Finalize procedure is called". If the phrase "The object is of type Z" is equivalent to "The object's nominal type is Z", for objects declared by an object_declaration, as 3.3.1(8) would seem to imply, then there's a problem if T is an interface type: Obj : Int'Class := ; because the "specific type identified by the tag" (this is the phrase used in other places in the RM) may be a controlled or a non-controlled type; thus, when Obj is finalized, it can't be determined statically whether any Finalize routine needs to be called. But Finalize definitely needs to be called if the specific type is controlled, right? It looks to me that when 7.6.1(7) and probably (9), refer to the type of an object, the "type" here needs to mean the "specific type identified by the tag, if the object is tagged". I don't know whether the current wording clearly means that, or a change is needed. Also, I haven't yet learned anything about synchronized interfaces, so I don't know what the effect on (8) is, but that's probably affected too. (Also, I'm just picking on 7.6.1(7-9) here, but there are undoubtedly other places dealing with Adjust and Finalize that have the same issue.) **************************************************************** From: Tucker Taft Sent: Wednesday, April 9, 2008 8:56 PM This is probably a general issue of static semantics vs. dynamic semantics. From a static semantic point of view, there is no doubt that the "type of Obj" is T'Class. From a dynamic point of view, a given object can be viewed as any classwide type that covers it, so it really only makes sense to talk about the specific type when talking about "the" type of an object. It wouldn't hurt to make this distinction explicit. **************************************************************** From: Randy Brukardt Sent: Wednesday, April 9, 2008 8:56 PM >... > If the phrase "The object is of type Z" is equivalent to "The >object's nominal type is Z", for objects declared by an >object_declaration, This in itself can't possibly be true, because there is no such thing as a "nominal type". I suppose you actually mean "The type of the object's nominal subtype is Z". (If you are going to be pedantic, you have to go all the way... :-) >... as 3.3.1(8) would seem to imply, then there's a problem if T is an >interface type: > > Obj : Int'Class := ; > > because the "specific type identified by the tag" (this is the phrase > used in other places in the RM) may be a controlled or a > non-controlled type; thus, when Obj is finalized, it can't be > determined statically whether any Finalize routine needs to be called. > But Finalize definitely needs to be called if the specific type is > controlled, right? Surely. But the rule in question is a dynamic semantics rule, and we don't want to be worrying about anything statically. So I think you are right, but for the wrong reasons: we shouldn't be talking about the type at all, only about its tag (which has the correct dynamic semantics). The rule probably should be something like: * If the object is of a tagged type, and the tag identifies a controlled type, the Finalize procedure is called. > It looks to me that when 7.6.1(7) and probably (9), refer to the type > of an object, the "type" here needs to mean the "specific type > identified by the tag, if the object is tagged". I don't think it makes sense to change (9) this way, but it suggests that there is a very general problem with the Standard. Maybe we simply need to define the "dynamic type" of an object, for use in dynamic rules. Of course it is not a real problem, since class-wide types don't exist at runtime, and these are only runtime rules. Thus I don't see how anyone could get this wrong (and thus it fails the Duff test). > I don't know whether > the current wording clearly means that, or a change is needed. If it does, I couldn't find it. It's a clear problem caused by mixing static and dynamic concepts, because you'll always have trouble when they are different. > (Also, I'm just picking on 7.6.1(7-9) here, but there are undoubtedly > other places dealing with Adjust and Finalize that have the same > issue.) I think it is any place that you have a dynamic semantics rule talking about the type of an object. (It's surely not limited to controlled types.) Hopefully Tucker will explain that this is all obvious. ;-) [Unfortunately, he beat me to answering this by seconds, and he didn't explain that it is obvious. - RLB] **************************************************************** From: Randy Brukardt Sent: Friday, July 11, 2008 6:18 PM The (draft) minutes from the recent meeting say for AI05-0099-1: Tucker wonders about privacy, this wording doesn't cover that. An untagged private type can be completed with a tagged type. Randy tries to point out that dynamic semantics ignore privacy. But then Tucker says that there is nothing wrong with the original wording. So most feel that a Ramification is more appropriate. Rewrite the AI as a ramification with just a To Be Honest AARM note. Approve intent of AI: 7-0-1. --- There are only two problems with this resolution: (1) It's not responsive to the question in the AI; (2) It's inconsistent with the way that the rest of the language handles similar cases. Let me explain. Adam's original question was about an object whose nominal subtype is a class-wide interface type, and whose object (created by some constructor function) has a tag identifying a controlled type that implements that interface. That class-wide type is surely not a controlled type, yet we hope (expect?) that the object gets finalized. The discussion about privacy mentioned in the minutes is correct as far as it goes; Tucker is surely correct that there is nothing wrong with the original wording vis-a-vis privacy. But that is irrelevant to answering the question, which was how the type is determined for a class-wide type. One could try to argue that using the specific type in such a case is how the language works. But in that case, it would be necessary to provide some proof - some existing wording to that effect. Which brings us to the second point. In an attempt to figure out the proof, I looked at some similar cases in the language: Membership operations - 4.5.2(30.1/2) says: if the type of the simple_expression is class-wide, the value has a tag that identifies a type covered by the tested type; Type conversions - 4.6(42) says: The tag of the result is that of the operand. If the operand type is class-wide, a check is made that the tag of the operand identifies a (specific) type that is covered by or descended from the target type. Both of these wordings are quite clear that for class-wide types, we forget the type and do the operation based on the tag of the object. And note that in both cases, they specifically mention this case. They don't depend on some magical meaning of type defined elsewhere. Now, it's true that the original wording of 7.6.1(7) and 7.6.1(8) worked fine for Ada 95. Since all controlled types are descended from a single root type, any class-wide type that covers a controlled type must also be a controlled type. And protected types can't ever be tagged. So the only issue is privacy, and for that we can ignore it as this is dynamic semantics. However, once we add interface types to this mix, none of that is true. A synchronized interface class-wide type could have an object that is either a protected object or a task, and the interface is considered to be neither. Similarly, an interface class-wide type can have an object that is controlled, or one that is not, but surely the interface is not controlled (it is not descended from one of the root controlled types). The wording I proposed attempted to handle this problem with a minimum of wording. But I'm not wedded to that wording -- but I'm certain we do need wording to handle at least class-wide case. If we can make the privacy explicit, so much the better. One heavier way to do this would be to define the dynamic type of an object: The *dynamic type* of an object is: * If the full type of the nominal subtype of the object is tagged, the dynamic type is the type identified by the tag of the object; * Otherwise, the dynamic type is the full type of the object. [I covered all tagged types in the first bullet so that this term would work in the future on formal parameters, for which the nominal subtype and the *real* type can differ even for static types. If we're going to define a term, it seems likely that it will get reused. But that's not necessary for this use, so it could just cover the class-wide case.] Then rewrite the bullets 7.6.1(6-9) to say "If the dynamic type of the object is ", rather than "If the object is of a type". Another alternative would be to leave the existing text alone, but to add another bullet to specifically call out the class-wide case: * If the object is of a class-wide type, the finalization action appropriate for the type identified by the tag of the object is performed; I find this a bit funky, because it overlaps the other cases, and is recursive, into a set of bullets that is already somewhat ordered. Finally, here is my original attempt at revising 7.6.1(7-8): * If the object is of a tagged type, and the tag of the object identifies a controlled type, the Finalize procedure of that controlled type is called. * If the object is of a protected type, or if the object is of a tagged type and the tag of the object identifies a protected type, the the actions defined in 9.4 are performed; One could address the privacy issue with something like: * If the full type of the object is a tagged type, and the tag of the object identifies a controlled type, the Finalize procedure of that controlled type is called. although that's not strictly necessary, given that the implicit "view of" does not apply to dynamic semantics. Any of these would work, and probably there are variations that would work as well. --- Anyway, if the group still wants a Ramification only, we'll need to find another author (in the absence of someone finding existing wording that covers this), because I have no interest in writing an AI that I would have to vote against in the next meeting. **************************************************************** From: Tucker Taft Sent: Sunday, July 13, 2008 9:17 PM I wonder if we could generalize the definition of "part" to cover this case? That is, when we say if a "part" of an object is controlled/protected, that includes the case where it is of a class-wide type for an interface and the tag identifies a controlled/protected type. I guess my main concern is that I would like something that works in general, rather than this being another thing we have to keep worrying about every time we write a dynamic-semantics rule. **************************************************************** From: Randy Brukardt Sent: Tuesday, July 29, 2008 6:17 PM Revisiting this issue so I can proceed with it in some way. Tucker [1] replied on July 13th: > I wonder if we could generalize the definition of "part" to cover this > case? That is, when we say if a "part" of an object is > controlled/protected, that includes the case where it is of a > class-wide type for an interface and the tag identifies a > controlled/protected type. > > I guess my main concern is that I would like something that works in > general, rather than this being another thing we have to keep worrying > about every time we write a dynamic-semantics rule. Tucker [2] wrote yesterday: > By the way, why don't we officially adopt the term the "specific type > of an object" as a solution to the problem we were wrestling with a > few weeks ago about the meaning of "type" of an object in dynamic > semantics, when its declared type is class-wide? That is, "specific > type of an object" is the type determined by its tag, while the > "declared type of an object" is the type determined by its > declaration. We should use one or the other in dynamic semantic > rules. We shouldn't just say "type" except in static semantics and > legality rules. And even in static semantics, we might talk about the > "specific type of an object" created by an allocator. Humm. I'm having a hard time reconciling Tucker [1] and Tucker [2], particularly without any input from the rest of the ARG. Tucker [1]'s suggestion of changing "part" seems very risky, given the number of rules that use part as a technical term. But I surely sympathize with his concern about having a continual concern in dynamic semantics rules. OTOH, Tucker [2] seems to be saying "let's start over and rewrite *all* of the dynamic semantic rules that talk about type"! Besides not really helping with the continual concern with new rules (we'd always have to remember to not use "type"), that seems to be too much of a change for too little reason. My research into this problem shows that the language does in fact have wording to avoid depending on the type of class-wide objects in the dynamic semantics rules that I checked. 7.6.1 didn't need such a rule in Ada 95 (because any class-wide type would necessarily be controlled if the specific types could be controlled). So I think the real problem is actually limited to Adam's question (7.6.1(7) and 7.6.1(8) do not work as written for class-wide interface types). Making changes beyond that doesn't seem to be justified given the known scope of the problem. If we later find more instances of the problem, we should worry about generalizing it then. So, at this point, I still think the minimum change is the best idea. Given that that was rejected (more or less) in Venice, I'm not sure how to proceed. I don't want to bring back essentially the same proposal with a minor tweak unless there is more agreement that it is the right course. (I don't want to act like I'm above the process here; I just don't want to waste time writing an AI that is not responsive to the question that was asked.) Here's the wording I'm proposing now (adding only "full type" to the wording so that the ignoring of views is crystal clear, although no one thought that necessary for Ada 95) to replace 7.6.1(7-8): * If the full type of the object is of a tagged type, and the tag of the object identifies a controlled type, the Finalize procedure of that controlled type is called; * If the full type of the object is of a protected type, or if the full type of the object is of a tagged type and the tag of the object identifies a protected type, the actions defined in 9.4 are performed; This isn't very similar to the wording used elsewhere for class-wide cases, but the only way to make it similar would be to add a bullet like: * If the full type of the object is of a class-wide type, the finalization action appropriate for the type identified by the tag of the object is performed; after 7.6.1(8) [leaving 7.6.1(7-8) alone except for the full type stuff]. I find that rather squirrelly, as this bullet would overlap 7.6.1(7) [as a class-wide type can be a controlled type]. We could say "interface class-wide type" in order to avoid that, but then the rule looks more like a wart than something intended [and it is not a wart, it is intended]. And in any case it is a bit weird: "action appropriate for the type identified by the tag?" Thoughts? **************************************************************** From: Robert A. Duff Sent: Wednesday, July 30, 2008 8:06 AM > So, at this point, I still think the minimum change is the best idea. Here's what I think: During "language design", one should try hard to get everything exactly right. During "language maintenance", one should stay closer to the "if it ain't broke, don't fix it" idea. This is language maintenance, so we should just fix the specific problem, as your proposed wording does. ****************************************************************