Version 1.7 of ai05s/ai05-0099-1.txt
!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 WG9 Approved 09-06-12
!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 := <expression>;
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)
Replace the paragraph:
- If the object is of an elementary type, finalization
has no effect;
by:
- If the full type of the object is an elementary type, finalization
has no effect;
!corrigendum 7.6.1(7)
Replace the paragraph:
- If the object is of a controlled type, the Finalize procedure is
called;
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;
!corrigendum 7.6.1(8)
Replace the paragraph:
- If the object is of a protected type, the actions defined in
9.4 are performed;
by:
- If the full type of the object is 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;
!corrigendum 7.6.1(9/2)
Replace the paragraph:
- If the object is of a composite type, then after performing the
above actions, if any, every component of the object
is finalized in an arbitrary order, except as follows:
if the object has a component with an access discriminant constrained
by a per-object expression, this component is finalized before any
components that do not have such discriminants; for an object with
several components with such a discriminant, they are finalized in the
reverse of the order of their component_declarations;
by:
- If the full type of the object is a composite type, then after
performing the above actions, if any, every component of the object
is finalized in an arbitrary order, except as follows:
if the object has a component with an access discriminant constrained
by a per-object expression, this component is finalized before any
components that do not have such discriminants; for an object with
several components with such a discriminant, they are finalized in the
reverse of the order of their component_declarations;
!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.
!ASIS
No change needed.
!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 := <expression>;
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 := <expression>;
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 := <expression>;
>
> 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 <something>", rather than "If the object is of a <something> 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.
****************************************************************
Questions? Ask the ACAA Technical Agent