comp.lang.ada
 help / color / mirror / Atom feed
From: Robert A Duff <bobduff@shell01.TheWorld.com>
Subject: Re: Why is the destructor called multiple times after I declare an object?
Date: Tue, 12 Jan 2016 19:02:18 -0500
Date: 2016-01-12T19:02:18-05:00	[thread overview]
Message-ID: <wccbn8qz6r9.fsf@shell01.TheWorld.com> (raw)
In-Reply-To: n73pq5$p6o$1@gioia.aioe.org

"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> On 2016-01-12 21:21, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:n72hag$bjq$1@gioia.aioe.org...
>>> On 12/01/2016 00:44, Randy Brukardt wrote:
>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>>> news:n715oq$fae$1@gioia.aioe.org...
>>>>> On 2016-01-11 19:17, Bob Duff wrote:
>>>>>> Build-in-place is done for return of immutably-limited types,
>>>>>> whether or not the extended return syntax is used.
>>>>>
>>>>> But you can leave one return statement on an exception, catch the
>>>>> exception, and then return through another return statement, with other
>>>>> discriminants and even other type of the result (if it is class-wide).

Yes.  Or you can 'goto' or 'exit' out of an extended return.

>>>>> Therefore the result can be potentially allocated and reallocated any
>>>>> number of times. In which sense is this behavior 'in-place'?

"In place" means that the returned object created by the return
statement that actually returns is the same object as the one at the
call site.  If the return statement raises an exception, then it doesn't
actually return.

Note that this point has nothing to do with extended_return syntax.
An old fashioned "return <expression>;" can raise an exception,
and be handled, and then do a different return.  The syntax doesn't
matter; build-in-place is controlled by "immutably limited".

>>>     return Candidate_1 : T (Size => 1) do
>>>        Size := Candidate_1.Get_Required_Size;
>>>        raise Try_Again;
>>>     end return;
>>> exception
>>>     when Try_Again =>
>>>        return Candidate_2 : T (Size => Size) do
>>>            ...
>>>        end return;
>>>
>>> Since Ada lacks proper user-defined constructors one cannot claim that
>>> Candidate_1 was not fully constructed. Even its Initialize was through.
>>
>> But this is *not* a temporary object. The final object might change identity
>> in such a scenario, but Candidate_1 and Candidate_2 are the *same* object,
>> with different properties.

No, that's not right.  Candidate_1 is an object created by the first
return statement, and finalized during "raise Try_Again;".  It no
longer exists when Candidate_2 is created.  If Candidate_2 is returned
(there's no more raise/goto/whatever in there), then Candidate_2
is the same object as the one created at the call site.

> What makes two objects "same"? ...

The RM is clear on that point, and it is clear that the two candidates
are not the same object.

> Does RM specifically require the implementation to have
> Candidate_1'Address = Candidate_2'Address?

No, the RM says almost nothing about 'Address.  A garbage collector
could move objects around.  Access values are equal if and only if
they designate the same object (even in the presence of GC), but
Addresses are not (necessarily) so well behaved.

> The following program -------------------------->
> with Ada.Text_IO; use Ada.Text_IO;
> with System.Storage_Elements;  use System.Storage_Elements;
>
> procedure Test_Return is
>    package P is
>       type T is tagged limited null record;
>    end P;
>    package Q is
>       type S (L : Positive) is new P.T with record
>          X : String (1..L);
>       end record;
>    end Q;
>    function Create return P.T'Class is
>    begin
>       return Candidate_1 : P.T do
>          Put_Line (Integer_Address'Image (To_Integer
> (Candidate_1'Address)));
>          raise Constraint_Error;
>       end return;
>    exception
>       when Constraint_Error =>
>          return Candidate_2 : Q.S (1000) do
>             Put_Line (Integer_Address'Image (To_Integer
> (Candidate_2'Address)));
>          end return;
>    end Create;	
>    X : P.T'Class := Create;
> begin
>    null;
> end Test_Return;
> <----------------------------------------
> prints:
>>test_return
>  4454256
>  4454272
>
> Is GNAT at fault? Maybe "location" is not the memory address? And

The RM doesn't define "location".  And the rules about 'Address are
pretty loose.  And GNAT is correct here.

I think what Randy meant to say is that X (declared in Test_Return)
is the same object as Candidate_2.  That is what is required by the
RM, and it's what "build in place" means.  In GNAT, if you printed
X'Address it would match Candidate_2'Address, but that's not required
by the RM.  The two candidates are not the same object, as you
correctly noted.

If you had said:

    type Acc is access P.T'Class;
    X : Acc := new P.T'Class'(Create);

then Candidate_1 would get allocated on the heap, then finalized and
deallocated, then Candidate_2 would get allocated on the heap, and
X.all would end up being the same object as Candidate_2.

But keep in mind that the above example is quite unusual.  The normal
case is to have exactly one extended return.  And the size of the thing
is known at compile time, or at least known at the call site, so
the caller can allocate the result (stack, heap, whatever), and
pass the address of that to the function.

> 4. The same object allocated at two different memory addresses?
>
> Finally, I know that you don't consider RM subject to mathematical
> logic, ...

Now, now, that's just sniping.  We try to make the RM correct,
but we make mistakes.

- Bob


  reply	other threads:[~2016-01-13  0:02 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-11  1:37 Why is the destructor called multiple times after I declare an object? Andrew Shvets
2016-01-11  2:18 ` Jeffrey R. Carter
2016-01-11  3:35   ` Andrew Shvets
2016-01-11 17:02     ` Brian Drummond
2016-01-11 16:29   ` Brian Drummond
2016-01-11 17:20     ` Simon Wright
2016-01-11 18:17     ` Bob Duff
2016-01-11 21:10       ` Dmitry A. Kazakov
2016-01-11 23:44         ` Randy Brukardt
2016-01-12  9:33           ` Dmitry A. Kazakov
2016-01-12 20:21             ` Randy Brukardt
2016-01-12 21:05               ` Dmitry A. Kazakov
2016-01-13  0:02                 ` Robert A Duff [this message]
2016-01-13  8:31                   ` Dmitry A. Kazakov
2016-01-13  9:01                     ` Georg Bauhaus
2016-01-13 14:45                     ` J-P. Rosen
2016-01-13 20:09                       ` Dmitry A. Kazakov
2016-01-14  9:04                         ` J-P. Rosen
2016-01-14  9:47                           ` Dmitry A. Kazakov
2016-01-13 16:03                     ` Robert A Duff
2016-01-13 19:59                       ` Dmitry A. Kazakov
2016-01-14 10:04                         ` Georg Bauhaus
2016-01-14 13:42                           ` Dmitry A. Kazakov
2016-01-12 12:41       ` Brian Drummond
2016-01-13 20:18       ` Jacob Sparre Andersen
2016-01-14  1:31         ` Robert A Duff
2016-01-12  0:43     ` Jeffrey R. Carter
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox