* Why is the destructor called multiple times after I declare an object? @ 2016-01-11 1:37 Andrew Shvets 2016-01-11 2:18 ` Jeffrey R. Carter 0 siblings, 1 reply; 27+ messages in thread From: Andrew Shvets @ 2016-01-11 1:37 UTC (permalink / raw) Hello, This is the code in question: http://pastebin.com/zf7yEvpe When I run the executable, this is what I get: $ ./main_animal Resetting values of Creat to defaults. Resetting values of Creat to defaults. Resetting values of Creat to defaults. Resetting values of Creat to defaults. The animal: The name: dog Number of legs: 4 Weight in grams: 3000 Height in cm: 40 The animal: The name: Elephant Number of legs: 4 Weight in grams: 4000000 Height in cm: 500 Resetting values of Creat to defaults. Resetting values of Creat to defaults. Why is "Resetting values of Creat to defaults." displaying 6 times as opposed to just twice? ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 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 16:29 ` Brian Drummond 0 siblings, 2 replies; 27+ messages in thread From: Jeffrey R. Carter @ 2016-01-11 2:18 UTC (permalink / raw) On 01/10/2016 06:37 PM, Andrew Shvets wrote: > > Why is "Resetting values of Creat to defaults." displaying 6 times as opposed to just twice? ARM 7.6(13-17.1) apply here. Note that Init declares a local variable of the type, which is finalized when Init returns, and that the anonymous object that is the result of the call to Init is finalized after initialization is finished. This gives you 2 calls to Finalize for each variable of the type declared and initialized by a call to Init. Finally you have a call to Finalize for each variable of the type when the program ends. http://www.adaic.org/resources/add_content/standards/12rm/html/RM-7-6.html -- Jeff Carter "Death awaits you all, with nasty, big, pointy teeth!" Monty Python & the Holy Grail 20 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 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 1 sibling, 1 reply; 27+ messages in thread From: Andrew Shvets @ 2016-01-11 3:35 UTC (permalink / raw) On Sunday, January 10, 2016 at 9:18:57 PM UTC-5, Jeffrey R. Carter wrote: > On 01/10/2016 06:37 PM, Andrew Shvets wrote: > > > > Why is "Resetting values of Creat to defaults." displaying 6 times as opposed to just twice? > > ARM 7.6(13-17.1) apply here. Note that Init declares a local variable of the > type, which is finalized when Init returns, and that the anonymous object that > is the result of the call to Init is finalized after initialization is finished. > This gives you 2 calls to Finalize for each variable of the type declared and > initialized by a call to Init. Finally you have a call to Finalize for each > variable of the type when the program ends. > > http://www.adaic.org/resources/add_content/standards/12rm/html/RM-7-6.html > > -- > Jeff Carter > "Death awaits you all, with nasty, big, pointy teeth!" > Monty Python & the Holy Grail > 20 I see. Thank you for your explanation. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-11 3:35 ` Andrew Shvets @ 2016-01-11 17:02 ` Brian Drummond 0 siblings, 0 replies; 27+ messages in thread From: Brian Drummond @ 2016-01-11 17:02 UTC (permalink / raw) On Sun, 10 Jan 2016 19:35:43 -0800, Andrew Shvets wrote: > On Sunday, January 10, 2016 at 9:18:57 PM UTC-5, Jeffrey R. Carter > wrote: >> On 01/10/2016 06:37 PM, Andrew Shvets wrote: >> > >> > Why is "Resetting values of Creat to defaults." displaying 6 times as >> > opposed to just twice? >> >> ARM 7.6(13-17.1) apply here. Note that Init declares a local variable >> of the type, > > I see. Thank you for your explanation. Note that for the default initialisation case, if you override Initialize, it will be called automatically. overriding procedure Initialize( Creat : in out Creature) is begin Ada.Text_IO.Put_Line("Initializing values of Creat to defaults."); Creat.Name := Ada.Strings.Unbounded.To_Unbounded_String ("Ferret"); Creat.Legs := 3; Creat.WeightInGrams := 100; Creat.HeightInCm := 7; end Initialize; (yes the ferret lost a leg somehow). Because it's a procedure, with In Out parameters, it operates in-place, avoiding both the creation of a temporary object, and assignment. Now the main program Var1 : Animal.Creature; --:= Animal.Init; -- default constructor Var2 : Animal.Creature := Animal.Init("Elephant", 4, 4000000, 500); begin Animal.Print_Record(Var1); Animal.Print_Record(Var2); end main_animal; initialises both variables to the defaults, then operates as Jeffery answered for the non-default Init function (I overrode Adjust to track assignments). Initializing values of Creat to defaults. Initializing values of Creat to defaults. Adjusting Creature named Elephant Resetting values of Creat to defaults. Adjusting Creature named Elephant Resetting values of Creat to defaults. The animal: The name: Ferret Number of legs: 3 Weight in grams: 100 Height in cm: 7 The animal: The name: Elephant Number of legs: 4 Weight in grams: 4000000 Height in cm: 500 Resetting values of Creat to defaults. Resetting values of Creat to defaults. Rewriting Init (the non-default constructor) as a procedure would eliminate the intermediate variables and assignments. It would have to be called at the start of the main program instead of as an initialiser. Regrettably there seems to be no syntax for calling non- default initializers on a controlled type. -- Brian ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-11 2:18 ` Jeffrey R. Carter 2016-01-11 3:35 ` Andrew Shvets @ 2016-01-11 16:29 ` Brian Drummond 2016-01-11 17:20 ` Simon Wright ` (2 more replies) 1 sibling, 3 replies; 27+ messages in thread From: Brian Drummond @ 2016-01-11 16:29 UTC (permalink / raw) On Sun, 10 Jan 2016 19:18:53 -0700, Jeffrey R. Carter wrote: > On 01/10/2016 06:37 PM, Andrew Shvets wrote: >> >> Why is "Resetting values of Creat to defaults." displaying 6 times as >> opposed to just twice? > > ARM 7.6(13-17.1) apply here. Note that Init declares a local variable of > the type, which is finalized when Init returns, and that the anonymous > object that is the result of the call to Init is finalized after > initialization is finished. > This gives you 2 calls to Finalize for each variable of the type > declared and initialized by a call to Init. Finally you have a call to > Finalize for each variable of the type when the program ends. > > http://www.adaic.org/resources/add_content/standards/12rm/html/ RM-7-6.html Interesting. I thought you could eliminate one of those local copies using "extended return" in the Init function, as in: function Init return Creature is begin return TempCreature : Creature do TempCreature.Name := Ada.Strings.Unbounded.To_Unbounded_String("dog"); TempCreature.Legs := 4; TempCreature.WeightInGrams := 3000; TempCreature.HeightInCm := 40; end return; end Init; Somehow I expected "extended return" to allocate space and "build in place" during the execution of the return statement. Is this something legal that Gnat doesn't take advantage of? Or is there a Gnat option I'm not aware of? Of course instead of a default constructor, the record can be populated with default values, to eliminate both the "Init" call and two temporary objects, but the "problem" remains for the other constructor. -- Brian ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-11 16:29 ` Brian Drummond @ 2016-01-11 17:20 ` Simon Wright 2016-01-11 18:17 ` Bob Duff 2016-01-12 0:43 ` Jeffrey R. Carter 2 siblings, 0 replies; 27+ messages in thread From: Simon Wright @ 2016-01-11 17:20 UTC (permalink / raw) Brian Drummond <brian@shapes.demon.co.uk> writes: > Somehow I expected "extended return" to allocate space and "build in > place" during the execution of the return statement. > > Is this something legal that Gnat doesn't take advantage of? Or is > there a Gnat option I'm not aware of? ARM 7.6 (17.2-17.4) ff [1]: must build in place if the full type is (immutably) limited, or (contains components that are) controlled. Otherwise, up to the compiler. Doesn't say anything about extended return. [1] http://www.adaic.org/resources/add_content/standards/12rm/html/RM-7-6.html#p17.2 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 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 ` (2 more replies) 2016-01-12 0:43 ` Jeffrey R. Carter 2 siblings, 3 replies; 27+ messages in thread From: Bob Duff @ 2016-01-11 18:17 UTC (permalink / raw) Brian Drummond <brian@shapes.demon.co.uk> writes: > Somehow I expected "extended return" to allocate space and "build in > place" during the execution of the return statement. Build-in-place is done for return of immutably-limited types, whether or not the extended return syntax is used. For nonlimited types, the compiler is free to use build-in-place if it can prove that it's equivalent to return-by-copy. It's often not equivalent. For example: X := Init; What if Init raises an exception after partly modifying the result? In that case X should not be modified, so the result object of Init and X had better not be at the same address. - Bob ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 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 12:41 ` Brian Drummond 2016-01-13 20:18 ` Jacob Sparre Andersen 2 siblings, 1 reply; 27+ messages in thread From: Dmitry A. Kazakov @ 2016-01-11 21:10 UTC (permalink / raw) On 2016-01-11 19:17, Bob Duff wrote: > Brian Drummond <brian@shapes.demon.co.uk> writes: > >> Somehow I expected "extended return" to allocate space and "build in >> place" during the execution of the return statement. > > 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). Therefore the result can be potentially allocated and reallocated any number of times. In which sense is this behavior 'in-place'? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-11 21:10 ` Dmitry A. Kazakov @ 2016-01-11 23:44 ` Randy Brukardt 2016-01-12 9:33 ` Dmitry A. Kazakov 0 siblings, 1 reply; 27+ messages in thread From: Randy Brukardt @ 2016-01-11 23:44 UTC (permalink / raw) "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: >> Brian Drummond <brian@shapes.demon.co.uk> writes: >> >>> Somehow I expected "extended return" to allocate space and "build in >>> place" during the execution of the return statement. >> >> 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). > > Therefore the result can be potentially allocated and reallocated any > number of times. In which sense is this behavior 'in-place'? "Build-in-place" means simply that there is no temporary object, the object is created directly in its final resting place (that is the memory where it will live during its existence). Whatever amount of effort it takes to figure out that final resting place is not part of the equation. For many situations (and implementation models), the size of the result object will not change regardless of discriminants chosen, so the sort of thing you describe above cannot happen. For assignments to most existing objects, the discriminants/tag cannot be changed, and 6.5(24/3) allows the Constraint_Error exception to be raised early in scenarios like the one you lay out. (Such an exception cannot be handled within the function, as it happens at the call-site.) If the discriminants are mutable, the compiler already has to have some mechanism for changing them [either by using allocate-to-the-max or reallocation], and build-in-place uses that same mechanism, without the temporary. You'd get the same behavior when assigning some other object as with a build-in-place function.) Randy. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-11 23:44 ` Randy Brukardt @ 2016-01-12 9:33 ` Dmitry A. Kazakov 2016-01-12 20:21 ` Randy Brukardt 0 siblings, 1 reply; 27+ messages in thread From: Dmitry A. Kazakov @ 2016-01-12 9:33 UTC (permalink / raw) 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: >>> Brian Drummond <brian@shapes.demon.co.uk> writes: >>> >>>> Somehow I expected "extended return" to allocate space and "build in >>>> place" during the execution of the return statement. >>> >>> 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). >> >> Therefore the result can be potentially allocated and reallocated any >> number of times. In which sense is this behavior 'in-place'? > > "Build-in-place" means simply that there is no temporary object, the object > is created directly in its final resting place (that is the memory where it > will live during its existence). > > Whatever amount of effort it takes to figure out that final resting place is > not part of the equation. Yes, but you said 'no temporary object' which is untrue because a return statement creates exactly such an object. You could even use this object in order to create another one: 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. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-12 9:33 ` Dmitry A. Kazakov @ 2016-01-12 20:21 ` Randy Brukardt 2016-01-12 21:05 ` Dmitry A. Kazakov 0 siblings, 1 reply; 27+ messages in thread From: Randy Brukardt @ 2016-01-12 20:21 UTC (permalink / raw) "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: >>>> Brian Drummond <brian@shapes.demon.co.uk> writes: >>>> >>>>> Somehow I expected "extended return" to allocate space and "build in >>>>> place" during the execution of the return statement. >>>> >>>> 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). >>> >>> Therefore the result can be potentially allocated and reallocated any >>> number of times. In which sense is this behavior 'in-place'? >> >> "Build-in-place" means simply that there is no temporary object, the >> object >> is created directly in its final resting place (that is the memory where >> it >> will live during its existence). >> >> Whatever amount of effort it takes to figure out that final resting place >> is >> not part of the equation. > > Yes, but you said 'no temporary object' which is untrue because a return > statement creates exactly such an object. You could even use this object > in order to create another one: > > 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. The various limitations on using a function call as the parent part of an extension aggregate exist specifically because of this effect. For a inherently limited type (the kind that requires build-in-place), the location of the object is part of its identity, argubly the most important part. (I realize that you might be defining "object" in your own way, which as always is irrelevant; I'm using the definition of "object" and "temporary object" as used in the Ada Standard.) Randy. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-12 20:21 ` Randy Brukardt @ 2016-01-12 21:05 ` Dmitry A. Kazakov 2016-01-13 0:02 ` Robert A Duff 0 siblings, 1 reply; 27+ messages in thread From: Dmitry A. Kazakov @ 2016-01-12 21:05 UTC (permalink / raw) 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: >>>>> Brian Drummond <brian@shapes.demon.co.uk> writes: >>>>> >>>>>> Somehow I expected "extended return" to allocate space and "build in >>>>>> place" during the execution of the return statement. >>>>> >>>>> 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). >>>> >>>> Therefore the result can be potentially allocated and reallocated any >>>> number of times. In which sense is this behavior 'in-place'? >>> >>> "Build-in-place" means simply that there is no temporary object, the >>> object >>> is created directly in its final resting place (that is the memory where >>> it >>> will live during its existence). >>> >>> Whatever amount of effort it takes to figure out that final resting place >>> is >>> not part of the equation. >> >> Yes, but you said 'no temporary object' which is untrue because a return >> statement creates exactly such an object. You could even use this object >> in order to create another one: >> >> 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. What makes two objects "same"? Especially if: 1. none of them exists at the same time as another 2. one of them is already finalized 3. they have different specific types, discriminats, components If T were not limited would they be same too? > For a inherently limited type (the kind that requires build-in-place), the > location of the object is part of its identity, argubly the most important > part. What is "location"? Does RM specifically require the implementation to have Candidate_1'Address = Candidate_2'Address? 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 4. The same object allocated at two different memory addresses? Finally, I know that you don't consider RM subject to mathematical logic, but in logic partial identity is just meaningless. E.g. you may say that the highest order digit is the most important part of number, but that does not imply two numbers same when their highest order digits are same. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-12 21:05 ` Dmitry A. Kazakov @ 2016-01-13 0:02 ` Robert A Duff 2016-01-13 8:31 ` Dmitry A. Kazakov 0 siblings, 1 reply; 27+ messages in thread From: Robert A Duff @ 2016-01-13 0:02 UTC (permalink / raw) "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 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-13 0:02 ` Robert A Duff @ 2016-01-13 8:31 ` Dmitry A. Kazakov 2016-01-13 9:01 ` Georg Bauhaus ` (2 more replies) 0 siblings, 3 replies; 27+ messages in thread From: Dmitry A. Kazakov @ 2016-01-13 8:31 UTC (permalink / raw) On 13/01/2016 01:02, Robert A Duff wrote: > "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. It is rather a useless definition, because it would apply to the objects returned by-copy as well. At some point *some* object created as a result of a call to the callee becomes the object of the caller. To my understanding Randy's definition tried to address this by claiming absence of intermediate objects (as a generalization of the notion of copying). > Note that this point has nothing to do with extended_return syntax. Right. Also neither and no definition will work ever. Whichever syntax "same" object cannot be "returned". > The RM doesn't define "location". And the rules about 'Address are > pretty loose. And GNAT is correct here. I didn't doubt it. The example was for the sake of argument. If RM attempted to define "same" location in a useful way that would make reasonable implementations impossible. > Now, now, that's just sniping. Yes, yes, I fired back at an attempt to evade discussion by the game of definitions. (:-)) -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 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 16:03 ` Robert A Duff 2 siblings, 0 replies; 27+ messages in thread From: Georg Bauhaus @ 2016-01-13 9:01 UTC (permalink / raw) On 13.01.16 09:31, Dmitry A. Kazakov wrote: > >> Now, now, that's just sniping. > > Yes, yes, I fired back at an attempt to evade discussion by the game of definitions. (:-)) Of mathematical logic? SCNR -- "HOTDOGS ARE NOT BOOKMARKS" Springfield Elementary teaching staff ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 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-13 16:03 ` Robert A Duff 2 siblings, 1 reply; 27+ messages in thread From: J-P. Rosen @ 2016-01-13 14:45 UTC (permalink / raw) Le 13/01/2016 09:31, Dmitry A. Kazakov a écrit : > On 13/01/2016 01:02, Robert A Duff wrote: >> "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. > > It is rather a useless definition, because it would apply to the objects > returned by-copy as well. At some point *some* object created as a > result of a call to the callee becomes the object of the caller. > OK, let's state it differently. The called function builds its result "somewhere". That "somewhere" is what will be used by the caller as the variable being initialized. It is perfectly OK if the function starts building the result in "somewhere_1", then decides to switch to "somewhere_2", as long as the eventual "somewhere" is what is used by the caller, /without copy/. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-13 14:45 ` J-P. Rosen @ 2016-01-13 20:09 ` Dmitry A. Kazakov 2016-01-14 9:04 ` J-P. Rosen 0 siblings, 1 reply; 27+ messages in thread From: Dmitry A. Kazakov @ 2016-01-13 20:09 UTC (permalink / raw) On 2016-01-13 15:45, J-P. Rosen wrote: > Le 13/01/2016 09:31, Dmitry A. Kazakov a écrit : >> On 13/01/2016 01:02, Robert A Duff wrote: >>> "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. >> >> It is rather a useless definition, because it would apply to the objects >> returned by-copy as well. At some point *some* object created as a >> result of a call to the callee becomes the object of the caller. >> > OK, let's state it differently. The called function builds its result > "somewhere". That "somewhere" is what will be used by the caller as the > variable being initialized. A non-limited result is built "somewhere", just the same. I think in-place must be a definite place, not just "somewhere". > It is perfectly OK if the function starts building the result in > "somewhere_1", then decides to switch to "somewhere_2", as long as the > eventual "somewhere" is what is used by the caller, /without copy/. "Without copy" requires a definition too. IMO, it must mean that no type operations are called otherwise than on the final result (function arguments do not count). For example, Initialize must be called strictly once. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-13 20:09 ` Dmitry A. Kazakov @ 2016-01-14 9:04 ` J-P. Rosen 2016-01-14 9:47 ` Dmitry A. Kazakov 0 siblings, 1 reply; 27+ messages in thread From: J-P. Rosen @ 2016-01-14 9:04 UTC (permalink / raw) Le 13/01/2016 21:09, Dmitry A. Kazakov a écrit : >> OK, let's state it differently. The called function builds its result >> "somewhere". That "somewhere" is what will be used by the caller as the >> variable being initialized. > > A non-limited result is built "somewhere", just the same. I think > in-place must be a definite place, not just "somewhere". In the non-limited case, copying is allowed (although not required), so there is no issue. What I mean is that it can work the other way round from your mental model: you think of the caller allocating the result space, and the function using that space; but it can be the function that choses where to build the result, and then the caller using that space for the object. It may not be the usual stack model, but that's irrelevant (we already know that a secondary stack may be used in some cases). >> It is perfectly OK if the function starts building the result in >> "somewhere_1", then decides to switch to "somewhere_2", as long as the >> eventual "somewhere" is what is used by the caller, /without copy/. > > "Without copy" requires a definition too. IMO, it must mean that no type > operations are called otherwise than on the final result (function > arguments do not count). For example, Initialize must be called strictly > once. "Without copy" means that the value constructed and returned by the function should not be moved to a different memory location. What else? -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-14 9:04 ` J-P. Rosen @ 2016-01-14 9:47 ` Dmitry A. Kazakov 0 siblings, 0 replies; 27+ messages in thread From: Dmitry A. Kazakov @ 2016-01-14 9:47 UTC (permalink / raw) On 14/01/2016 10:04, J-P. Rosen wrote: > Le 13/01/2016 21:09, Dmitry A. Kazakov a écrit : >>> OK, let's state it differently. The called function builds its result >>> "somewhere". That "somewhere" is what will be used by the caller as the >>> variable being initialized. >> >> A non-limited result is built "somewhere", just the same. I think >> in-place must be a definite place, not just "somewhere". > In the non-limited case, copying is allowed (although not required), so > there is no issue. What I mean is that it can work the other way round > from your mental model: you think of the caller allocating the result > space, and the function using that space; but it can be the function > that choses where to build the result, and then the caller using that > space for the object. It may not be the usual stack model, but that's > irrelevant (we already know that a secondary stack may be used in some > cases). For many (most, actually) important cases this is relevant, e.g. for an initialized limited component of a container object or a parent of. There is no way to do this without exposing all innards and even with exposing them chances are very high it won't work anyway. >>> It is perfectly OK if the function starts building the result in >>> "somewhere_1", then decides to switch to "somewhere_2", as long as the >>> eventual "somewhere" is what is used by the caller, /without copy/. >> >> "Without copy" requires a definition too. IMO, it must mean that no type >> operations are called otherwise than on the final result (function >> arguments do not count). For example, Initialize must be called strictly >> once. > "Without copy" means that the value constructed and returned by the > function should not be moved to a different memory location. > What else? You mean "object constructed" (the object refers to a value). I think that "copy" should be stated in terms of operations defined on the object. If the client cannot tell difference through legal operation then it is OK. Therefore the requirement that Initialize and other elaboration stuff must be performed once. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 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 16:03 ` Robert A Duff 2016-01-13 19:59 ` Dmitry A. Kazakov 2 siblings, 1 reply; 27+ messages in thread From: Robert A Duff @ 2016-01-13 16:03 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > It is rather a useless definition, because it would apply to the objects > returned by-copy as well. At some point *some* object created as a > result of a call to the callee becomes the object of the caller. No, nonlimited objects work differently. Consider: package P is type Doubly_Linked_List; type Node_Ptr is access all Doubly_Linked_List; type Doubly_Linked_List is limited record Next, Prev: Node_Ptr; Payload: Integer; end record; function Empty_List return Doubly_Linked_List; Global: Node_Ptr; end P; package body P is function Empty_List return Doubly_Linked_List is begin return Result: aliased Doubly_Linked_List do Result.Next := Result'Unchecked_Access; Result.Prev := Result'Unchecked_Access; Global := Result'Unchecked_Access; end return; end Empty_List; end P; with Text_IO; use Text_IO; procedure P.Main is My_List: aliased Doubly_Linked_List := Empty_List; begin Put_Line(Boolean'(Global = My_List'Unchecked_Access)'Img); Put_Line(Boolean'(My_List.Next = My_List'Unchecked_Access)'Img); Put_Line(Boolean'(My_List.Prev = My_List'Unchecked_Access)'Img); end P.Main; The example must print TRUE three times. In Empty_List, we set three pointers pointing to Result. After the call they point to My_List. That's because My_List and Result are the same object. If the implementation chooses to put My_List at a different location than Result, and copy Result into My_List, it would have to update those pointers, which is not easy. The intended implementation is to make sure that My_List and Result are at the same address. My_List is of known size, so it is allocated at the declaration, and its address is passed to Empty_List, so it knows where to put Result. If the size were not known at the call site, things would be more complicated -- it passes information about where to allocate (on the stack, on the global heap, in some user-defined storage pool, ...), and the function would do the allocation once it knows the size, and passes the address back to the caller. If we erase "limited", then the example is illegal -- Result can't be aliased. If that were allowed, then all three pointers would be dangling pointers, and the Put_Lines would all be erroneous. That's because Result and My_List are NOT the same object in the nonlimited case, and Result is gone by the time the Put_Lines are executed. > To my understanding Randy's definition tried to address this by claiming > absence of intermediate objects (as a generalization of the notion of > copying). > >> Note that this point has nothing to do with extended_return syntax. > > Right. Also neither and no definition will work ever. Whichever syntax > "same" object cannot be "returned". Two access values are "=" if and only if they designate the same object. See example above. QED. >> The RM doesn't define "location". And the rules about 'Address are >> pretty loose. And GNAT is correct here. > > I didn't doubt it. The example was for the sake of argument. If RM > attempted to define "same" location in a useful way that would make > reasonable implementations impossible. Agreed. >> Now, now, that's just sniping. > > Yes, yes, I fired back at an attempt to evade discussion by the game of > definitions. (:-)) ;-) - Bob ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-13 16:03 ` Robert A Duff @ 2016-01-13 19:59 ` Dmitry A. Kazakov 2016-01-14 10:04 ` Georg Bauhaus 0 siblings, 1 reply; 27+ messages in thread From: Dmitry A. Kazakov @ 2016-01-13 19:59 UTC (permalink / raw) On 2016-01-13 17:03, Robert A Duff wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> It is rather a useless definition, because it would apply to the objects >> returned by-copy as well. At some point *some* object created as a >> result of a call to the callee becomes the object of the caller. > > No, nonlimited objects work differently. Consider: > > package P is > > type Doubly_Linked_List; > type Node_Ptr is access all Doubly_Linked_List; > type Doubly_Linked_List is limited record > Next, Prev: Node_Ptr; > Payload: Integer; > end record; > > function Empty_List return Doubly_Linked_List; > > Global: Node_Ptr; > > end P; > > package body P is > > function Empty_List return Doubly_Linked_List is > begin > return Result: aliased Doubly_Linked_List do > Result.Next := Result'Unchecked_Access; > Result.Prev := Result'Unchecked_Access; > Global := Result'Unchecked_Access; > end return; > end Empty_List; > > end P; > > with Text_IO; use Text_IO; > procedure P.Main is > My_List: aliased Doubly_Linked_List := Empty_List; > begin > Put_Line(Boolean'(Global = My_List'Unchecked_Access)'Img); > Put_Line(Boolean'(My_List.Next = My_List'Unchecked_Access)'Img); > Put_Line(Boolean'(My_List.Prev = My_List'Unchecked_Access)'Img); > end P.Main; > > The example must print TRUE three times. In Empty_List, we set three > pointers pointing to Result. After the call they point to My_List. > That's because My_List and Result are the same object. Yes, but your definition still apply to all types. Some object must travel across the callee-caller border. That last object remains same regardless limited or not. > If we erase "limited", then the example is illegal -- Result can't be > aliased. If that were allowed, then all three pointers would be > dangling pointers, and the Put_Lines would all be erroneous. > That's because Result and My_List are NOT the same object > in the nonlimited case, and Result is gone by the time the > Put_Lines are executed. You could make it Controlled and fix pointers in Adjust. Your program will not notice a difference. >> To my understanding Randy's definition tried to address this by claiming >> absence of intermediate objects (as a generalization of the notion of >> copying). >> >>> Note that this point has nothing to do with extended_return syntax. >> >> Right. Also neither and no definition will work ever. Whichever syntax >> "same" object cannot be "returned". > > Two access values are "=" if and only if they designate the same > object. You can have different access values pointing same object (e.g. of two different access types) and, possibly, same access values pointing different objects (I believe Ada permits "near" access values for a segmented memory machine, then there is Unchecked_Union etc) > See example above. QED. Sure, some object is always returned and every object is always same to itself. This is not sufficient to define useful "in-place". In my view a definition must have the place known at the caller's context. E.g. to have the object: 1. Allocated at a specific machine address 2. Allocated by an allocator in the specific memory pool 3. Allocated as a specific component of a container object 4. Allocated as a parent of a derived type object The problem of returned object is that it conflates allocation with initialization. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-13 19:59 ` Dmitry A. Kazakov @ 2016-01-14 10:04 ` Georg Bauhaus 2016-01-14 13:42 ` Dmitry A. Kazakov 0 siblings, 1 reply; 27+ messages in thread From: Georg Bauhaus @ 2016-01-14 10:04 UTC (permalink / raw) On 13.01.16 20:59, Dmitry A. Kazakov wrote: > Sure, some object is always returned and every object is always same to itself. This is not sufficient to define useful "in-place". In my view a definition must have the place known at the caller's context. E.g. to have the object: > > 1. Allocated at a specific machine address > 2. Allocated by an allocator in the specific memory pool > 3. Allocated as a specific component of a container object > 4. Allocated as a parent of a derived type object > > The problem of returned object is that it conflates allocation with initialization. If Ada will have a way for the caller to express the placement of new objects to be constructed in situ by functions, might we then go back to just return-by-reference in the hope of abandoning "return-by-access"? I.e., in this case, the caller could request that a limited object be placed, e.g., on the stack, after having been initialized by the function. Or that it become a named component of some other object. -- "HOTDOGS ARE NOT BOOKMARKS" Springfield Elementary teaching staff ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-14 10:04 ` Georg Bauhaus @ 2016-01-14 13:42 ` Dmitry A. Kazakov 0 siblings, 0 replies; 27+ messages in thread From: Dmitry A. Kazakov @ 2016-01-14 13:42 UTC (permalink / raw) On 14/01/2016 11:04, Georg Bauhaus wrote: > On 13.01.16 20:59, Dmitry A. Kazakov wrote: >> Sure, some object is always returned and every object is always same >> to itself. This is not sufficient to define useful "in-place". In my >> view a definition must have the place known at the caller's context. >> E.g. to have the object: >> >> 1. Allocated at a specific machine address >> 2. Allocated by an allocator in the specific memory pool >> 3. Allocated as a specific component of a container object >> 4. Allocated as a parent of a derived type object >> >> The problem of returned object is that it conflates allocation with >> initialization. > > If Ada will have a way for the caller to express the placement of new > objects to be constructed in situ by functions, By procedures, of course. Initializer must a procedure. > might we then go back to just > return-by-reference in the hope of abandoning "return-by-access"? There is a simpler and cleaner way. What is needed is user-defined procedures implementing record/array component read and update access as primitive operations. No need to implement the syntax sugar X.M := F (...) literally as two separate evaluations of X.M and F(...) with inventing some intermediate objects to pass to some virtual assignment meaningless for limited types anyway. It should be Set_M (X, ...); with lots of problems with limited and indefinite types eliminated. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-11 18:17 ` Bob Duff 2016-01-11 21:10 ` Dmitry A. Kazakov @ 2016-01-12 12:41 ` Brian Drummond 2016-01-13 20:18 ` Jacob Sparre Andersen 2 siblings, 0 replies; 27+ messages in thread From: Brian Drummond @ 2016-01-12 12:41 UTC (permalink / raw) On Mon, 11 Jan 2016 13:17:20 -0500, Bob Duff wrote: > Brian Drummond <brian@shapes.demon.co.uk> writes: > >> Somehow I expected "extended return" to allocate space and "build in >> place" during the execution of the return statement. > > Build-in-place is done for return of immutably-limited types, > whether or not the extended return syntax is used. > > For nonlimited types, the compiler is free to use build-in-place if it > can prove that it's equivalent to return-by-copy. It's often not > equivalent. For example: > > X := Init; > > What if Init raises an exception after partly modifying the result? In > that case X should not be modified, so the result object of Init and X > had better not be at the same address. Thank you (and Simon and Brad) for the clarification. I had not considered the ramifications in the case of exceptions, and the impracticability of rolling back a partially modified object... -- Brian ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-11 18:17 ` Bob Duff 2016-01-11 21:10 ` 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 2 siblings, 1 reply; 27+ messages in thread From: Jacob Sparre Andersen @ 2016-01-13 20:18 UTC (permalink / raw) Bob Duff <bobduff@theworld.com> writes: > Brian Drummond <brian@shapes.demon.co.uk> writes: > For nonlimited types, the compiler is free to use build-in-place if it > can prove that it's equivalent to return-by-copy. It's often not > equivalent. For example: > > X := Init; > > What if Init raises an exception after partly modifying the result? > In that case X should not be modified, so the result object of Init > and X had better not be at the same address. But if: a) There is no exception handler between the assignment and leaving the scope of X, build-in-place is okay (but impractical)? b) The compiler can prove that no exceptions can occur after the first modification of the result inside Init, build-in-place is okay? Greetings, Jacob -- "The butcher backed into the meat grinder and got a little behind in his work." ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-13 20:18 ` Jacob Sparre Andersen @ 2016-01-14 1:31 ` Robert A Duff 0 siblings, 0 replies; 27+ messages in thread From: Robert A Duff @ 2016-01-14 1:31 UTC (permalink / raw) Jacob Sparre Andersen <sparre@nbi.dk> writes: > Bob Duff <bobduff@theworld.com> writes: >> Brian Drummond <brian@shapes.demon.co.uk> writes: > >> For nonlimited types, the compiler is free to use build-in-place if it >> can prove that it's equivalent to return-by-copy. It's often not >> equivalent. For example: >> >> X := Init; >> >> What if Init raises an exception after partly modifying the result? >> In that case X should not be modified, so the result object of Init >> and X had better not be at the same address. > > But if: > > a) There is no exception handler between the assignment and leaving the > scope of X, build-in-place is okay (but impractical)? Yes, I think that's OK. I think it's also practical in some cases. You also have to worry about the case where Init can see X. X isn't supposed to (appear to be) changed until return from Init. > b) The compiler can prove that no exceptions can occur after the first > modification of the result inside Init, build-in-place is okay? Yes. But it might be hard to prove that Storage_Error won't happen, for example. - Bob ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Why is the destructor called multiple times after I declare an object? 2016-01-11 16:29 ` Brian Drummond 2016-01-11 17:20 ` Simon Wright 2016-01-11 18:17 ` Bob Duff @ 2016-01-12 0:43 ` Jeffrey R. Carter 2 siblings, 0 replies; 27+ messages in thread From: Jeffrey R. Carter @ 2016-01-12 0:43 UTC (permalink / raw) On 01/11/2016 09:29 AM, Brian Drummond wrote: > > Somehow I expected "extended return" to allocate space and "build in > place" during the execution of the return statement. Extended return is required for a limited type other than returning a function call or aggregate. Limited types are build in place. But using an extended return for a non-build-in-place type makes no difference. > Is this something legal that Gnat doesn't take advantage of? Or is there > a Gnat option I'm not aware of? A compiler can eliminate the anonymous object if it can be sure the result is always the same as using it. It can build in place when not so required if it can be sure the result is always the same as not building in place. -- Jeff Carter "C's solution to this [variable-sized array parameters] has real problems, and people who are complaining about safety definitely have a point." Dennis Ritchie 25 ^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2016-01-14 13:42 UTC | newest] Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 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 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
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox