From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: 103376,f5508b044317ceed X-Google-Attributes: gid103376,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news1.google.com!postnews.google.com!m34g2000hsf.googlegroups.com!not-for-mail From: Adam Beneschan Newsgroups: comp.lang.ada Subject: Re: Question about controlled types. Date: Thu, 7 Feb 2008 08:47:48 -0800 (PST) Organization: http://groups.google.com Message-ID: References: <47aa5ca6$0$32487$4d3efbfe@news.sover.net> NNTP-Posting-Host: 66.126.103.122 Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Trace: posting.google.com 1202402869 25075 127.0.0.1 (7 Feb 2008 16:47:49 GMT) X-Complaints-To: groups-abuse@google.com NNTP-Posting-Date: Thu, 7 Feb 2008 16:47:49 +0000 (UTC) Complaints-To: groups-abuse@google.com Injection-Info: m34g2000hsf.googlegroups.com; posting-host=66.126.103.122; posting-account=duW0ogkAAABjRdnxgLGXDfna0Gc6XqmQ User-Agent: G2/1.0 X-HTTP-UserAgent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.12) Gecko/20050922 Fedora/1.7.12-1.3.1,gzip(gfe),gzip(gfe) Xref: g2news1.google.com comp.lang.ada:19732 Date: 2008-02-07T08:47:48-08:00 List-Id: On Feb 6, 5:19 pm, "Peter C. Chapin" 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