* Question about controlled types.
@ 2008-02-07 1:19 Peter C. Chapin
2008-02-07 4:54 ` Hyman Rosen
2008-02-07 16:47 ` Adam Beneschan
0 siblings, 2 replies; 7+ messages in thread
From: Peter C. Chapin @ 2008-02-07 1:19 UTC (permalink / raw)
I'm trying to understand the subtleties of controlled types. In the RM,
section 7.6, paragraph 17 (I'm looking at the Ada 2005 version) I see:
"For an assignment_statement, after the name and expression have been
evaluated, and any conversion (including constraint checking) has been
done, an anonymous object is created, and the value is assigned into it;
that is, the assignment operation is applied. (Assignment includes value
adjustment.) The target of the assignment_statement is then finalized.
The value of the anonymous object is then assigned into the target of
the assignment_statement. Finally, the anonymous object is finalized."
So suppose we have
type Ptr is access Whatever;
type Thing is new Ada.Finalization.Controlled with
record
P : Ptr;
end record;
Thus Things hold a handle to an object allocated on the heap. Now
suppose A and B are Things. Then consider
A := B;
If I understand the paragraph above, an anonymous object is created and
the values of B's components are copied into that object. Adjust is then
used on the anonymous object. Let's imagine that Adjust makes an
independent copy of the object accessed via the P component. If an
exception occurs during this adjustment (Storage_Error, say) the value
of A is not affected. This is good.
Next A is finalized and then the anonymous object is then assigned to A.
Here is my question: is Adjust used again to adjust the value of A? It
would seem so because the anonymous object is finalized after this and
we wouldn't want that finalization to disrupt A's eventual value (assume
Finalize deallocates the object accessed by the P component). However,
if that is all true then why use Adjust on the anonymous object?
It seems to me that a more appropriate sequence of events would be
1. Create the anonymous object as above (using Adjust, etc).
2. Finalize A as above.
3. Copy the components of the anonymous object to A without using Adjust.
4. Don't Finalize the anonymous object.
My concern here is exception safety. I'd like it to be the case that
when I do
A := B;
if there is insufficient memory to build a proper copy of B's complete
representation (including heap structures), I'd like A to be left
unchanged. Yet the semantics described in the RM seem to say that A will
be finalized (thus destroying its value) before the copy of B that
eventually gets stored in A is made. Thus if that copy operation fails
with Storage_Error, A is left corrupted.
This question seems very relevant to the Ada 2005 container library. For
example if A and B are vectors, and if B is a very large vector that I'm
trying to copy, I'd really like for A to be left unchanged should
Storage_Error occur during that copy.
Peter
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Question about controlled types.
2008-02-07 1:19 Question about controlled types Peter C. Chapin
@ 2008-02-07 4:54 ` Hyman Rosen
2008-02-07 16:30 ` Robert A Duff
2008-02-08 3:47 ` Peter C. Chapin
2008-02-07 16:47 ` Adam Beneschan
1 sibling, 2 replies; 7+ messages in thread
From: Hyman Rosen @ 2008-02-07 4:54 UTC (permalink / raw)
Peter C. Chapin wrote:
> 3. Copy the components of the anonymous object to A without using Adjust.
This is ill-advised. Objects may hold pointers to their own
submembers. If you assign without adjusting, those internal
pointers will point to the anonymous object, not to A.
There are reasons for doing assignment like this in Ada (or
at least I think so - I don't really know Ada), but the C++
assignment operator model is much cleaner.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Question about controlled types.
2008-02-07 4:54 ` Hyman Rosen
@ 2008-02-07 16:30 ` Robert A Duff
2008-02-08 3:31 ` Peter C. Chapin
2008-02-08 3:47 ` Peter C. Chapin
1 sibling, 1 reply; 7+ messages in thread
From: Robert A Duff @ 2008-02-07 16:30 UTC (permalink / raw)
Hyman Rosen <hyrosen@mail.com> writes:
> There are reasons for doing assignment like this in Ada (or
> at least I think so - I don't really know Ada), but the C++
> assignment operator model is much cleaner.
Right, the C++ way has the advantage that a single operation can get its
hands on the left- and right-hand sides at the same time. The reason
Ada doesn't have this feature is that we couldn't figure out how to make
it work for records whose discriminants can change. And we couldn't
simply outlaw that case, because it would introduce a violation of the
generic contract model.
- Bob
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Question about controlled types.
2008-02-07 1:19 Question about controlled types Peter C. Chapin
2008-02-07 4:54 ` Hyman Rosen
@ 2008-02-07 16:47 ` Adam Beneschan
2008-02-08 3:46 ` Peter C. Chapin
1 sibling, 1 reply; 7+ messages in thread
From: Adam Beneschan @ 2008-02-07 16:47 UTC (permalink / raw)
On Feb 6, 5:19 pm, "Peter C. Chapin" <pcha...@sover.net> wrote:
> I'm trying to understand the subtleties of controlled types. In the RM,
> section 7.6, paragraph 17 (I'm looking at the Ada 2005 version) I see:
>
> "For an assignment_statement, after the name and expression have been
> evaluated, and any conversion (including constraint checking) has been
> done, an anonymous object is created, and the value is assigned into it;
> that is, the assignment operation is applied. (Assignment includes value
> adjustment.) The target of the assignment_statement is then finalized.
> The value of the anonymous object is then assigned into the target of
> the assignment_statement. Finally, the anonymous object is finalized."
Did you read the rest of the paragraph? "As explained below, the
implementation may eliminate the intermediate anonymous object, so
this description subsumes the one given in 5.2, 'Assignment
Statements'". If you read the "below" part to which this sentence
refers, in the Implementation Permissions, you'll find that in the
case where an object is assigned to another object (i.e. not a
function call or an aggregate), you really need the intermediate
anonymous object only if there's the possibility of an overlap.
Suppose A is an array of controlled objects, and you say
A (2 .. 10) := A (1 .. 9);
Now a compiler might well decide to create a temporary object to hold
the array slice being assigned, because it will have to finalize
elements A(2) through A(9) before assigning them, and it will have to
store those values somewhere before doing that finalization. (Even in
that case, the temporary object isn't necessary since the compiler
could generate code to copy one element at a time.)
> So suppose we have
>
> type Ptr is access Whatever;
> type Thing is new Ada.Finalization.Controlled with
> record
> P : Ptr;
> end record;
>
> Thus Things hold a handle to an object allocated on the heap. Now
> suppose A and B are Things. Then consider
>
> A := B;
>
> If I understand the paragraph above, an anonymous object is created and
> the values of B's components are copied into that object.
Based on the Implementation Permission, I will bet that *no* compiler
will actually create an anonymous temporary object. A and B can't
overlap unless they're the same object (possible if one of them is a
subprogram parameter), and in that case the compiler could simply
generate code to check the addresses and see if they're the same
object.
> Adjust is then
> used on the anonymous object. Let's imagine that Adjust makes an
> independent copy of the object accessed via the P component. If an
> exception occurs during this adjustment (Storage_Error, say) the value
> of A is not affected. This is good.
>
> Next A is finalized and then the anonymous object is then assigned to A.
> Here is my question: is Adjust used again to adjust the value of A? It
> would seem so because the anonymous object is finalized after this and
> we wouldn't want that finalization to disrupt A's eventual value (assume
> Finalize deallocates the object accessed by the P component). However,
> if that is all true then why use Adjust on the anonymous object?
>
> It seems to me that a more appropriate sequence of events would be
>
> 1. Create the anonymous object as above (using Adjust, etc).
> 2. Finalize A as above.
> 3. Copy the components of the anonymous object to A without using Adjust.
> 4. Don't Finalize the anonymous object.
The trouble is, you're thinking about one particular use of controlled
types, where Adjust's sole purpose is to make a copy of the data
pointed to by a pointer (or multiple pointers). That's a common use,
but not the only possible use. Although I can't immediately think of
an example where your sequence would screw things up, the AARM refers
to subcomponents that are "self-referential or otherwise position-
dependent" (I think Hyman was referring to this same notion here).
> My concern here is exception safety. I'd like it to be the case that
> when I do
>
> A := B;
>
> if there is insufficient memory to build a proper copy of B's complete
> representation (including heap structures), I'd like A to be left
> unchanged. Yet the semantics described in the RM seem to say that A will
> be finalized (thus destroying its value) before the copy of B that
> eventually gets stored in A is made. Thus if that copy operation fails
> with Storage_Error, A is left corrupted.
>
> This question seems very relevant to the Ada 2005 container library. For
> example if A and B are vectors, and if B is a very large vector that I'm
> trying to copy, I'd really like for A to be left unchanged should
> Storage_Error occur during that copy.
Like I said above, A := B probably isn't going to involve an anonymous
object at all, because of the Implementation Permissions in this
section. This means that A will be finalized before any attempt is
made to copy the structure pointed to by B; if your idea is that A
must be unchanged if the copy of B could raise a Storage_Error, then
you'll probably have to roll your own:
procedure Safe_Assign (A : in out Thing; B : in Thing) is
Temp : Thing;
begin
Temp := B;
A.Ptr := Temp.Ptr;
Temp.Ptr := null;
end Safe_Assign;
I'll admit that that probably won't help with the container library,
though.
-- Adam
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Question about controlled types.
2008-02-07 16:30 ` Robert A Duff
@ 2008-02-08 3:31 ` Peter C. Chapin
0 siblings, 0 replies; 7+ messages in thread
From: Peter C. Chapin @ 2008-02-08 3:31 UTC (permalink / raw)
Robert A Duff wrote:
> Right, the C++ way has the advantage that a single operation can get its
> hands on the left- and right-hand sides at the same time. The reason
> Ada doesn't have this feature is that we couldn't figure out how to make
> it work for records whose discriminants can change. And we couldn't
> simply outlaw that case, because it would introduce a violation of the
> generic contract model.
That's interesting thanks.
Peter
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Question about controlled types.
2008-02-07 16:47 ` Adam Beneschan
@ 2008-02-08 3:46 ` Peter C. Chapin
0 siblings, 0 replies; 7+ messages in thread
From: Peter C. Chapin @ 2008-02-08 3:46 UTC (permalink / raw)
Adam Beneschan wrote:
> Did you read the rest of the paragraph? "As explained below, the
> implementation may eliminate the intermediate anonymous object, so
> this description subsumes the one given in 5.2, 'Assignment
> Statements'".
Well the anonymous object, and its existence or lack thereof, is not
what I'm worried about... I admit my earlier post may have been unclear
on that point. My main concern was in how to use controlled types in an
"exception safe" way.
However, it occurred to me today that if the implementation supports
garbage collection my example would work fine. In that case Finalize
wouldn't have to do anything. Adjust would still make a copy, but if
creating that copied failed during the assignment to A (the final
target), it would still be okay to share heap structures with the
anonymous object. When the anonymous object vanished those structures
would just be owned by A and not become garbage as they would have
otherwise.
Anyway, thanks for your detailed reply!
Peter
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Question about controlled types.
2008-02-07 4:54 ` Hyman Rosen
2008-02-07 16:30 ` Robert A Duff
@ 2008-02-08 3:47 ` Peter C. Chapin
1 sibling, 0 replies; 7+ messages in thread
From: Peter C. Chapin @ 2008-02-08 3:47 UTC (permalink / raw)
Hyman Rosen wrote:
> This is ill-advised. Objects may hold pointers to their own
> submembers. If you assign without adjusting, those internal
> pointers will point to the anonymous object, not to A.
Hmmm. I see what you are saying.
Peter
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2008-02-08 3:47 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-07 1:19 Question about controlled types Peter C. Chapin
2008-02-07 4:54 ` Hyman Rosen
2008-02-07 16:30 ` Robert A Duff
2008-02-08 3:31 ` Peter C. Chapin
2008-02-08 3:47 ` Peter C. Chapin
2008-02-07 16:47 ` Adam Beneschan
2008-02-08 3:46 ` Peter C. Chapin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox