* Limited_Controlled types as 'out' arguments @ 2003-07-30 11:31 Lutz Donnerhacke 2003-07-30 12:22 ` Dmitry A. Kazakov ` (2 more replies) 0 siblings, 3 replies; 25+ messages in thread From: Lutz Donnerhacke @ 2003-07-30 11:31 UTC (permalink / raw) I'm using an Limited_Controlled type as an 'out' parameter of a procedure. While programming this procedure in question, I wonder how to Finalize the object given as argument to the 'out' parameter. ------------------------------------------------------------------------ with Ada.Finalization; package t1 is type Test is new Ada.Finalization.Limited_Controlled with record a : Character; end record; procedure Initialize(o : in out Test); procedure Finalize(o : in out Test); procedure Copy(to : out Test; from : Test); end t1; ------------------------------------------------------------------------ with t1; use t1; procedure t is a, b, c : Test; begin Copy(a, b); Copy(a, c); end t; ------------------------------------------------------------------------ with Ada.Text_IO; use Ada.Text_IO; package body t1 is global : Character := '0'; procedure Initialize(o : in out Test) is begin o.a := global; Put_Line("Initializing " & o.a); global := Character'Succ(global); end Initialize; procedure Finalize(o : in out Test) is begin Put_Line("Finalizing " & o.a); end Finalize; procedure Copy(to : out Test; from : Test) is begin to.a := global; Put_Line("Copying " & from.a & " to " & to.a); global := Character'Succ(global); end Copy; end t1; ------------------------------------------------------------------------ This results in: Initializing 0 Initializing 1 Initializing 2 Copying 1 to 3 Copying 2 to 4 Finalizing 2 Finalizing 1 Finalizing 4 Clearly, the variable 0 and 3 are never finalized. How implement I this correctly (without refering to the rosen trick). ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 11:31 Limited_Controlled types as 'out' arguments Lutz Donnerhacke @ 2003-07-30 12:22 ` Dmitry A. Kazakov 2003-07-30 12:32 ` Lutz Donnerhacke 2003-07-30 12:31 ` Matthew Heaney 2003-07-30 12:37 ` Martin Dowie 2 siblings, 1 reply; 25+ messages in thread From: Dmitry A. Kazakov @ 2003-07-30 12:22 UTC (permalink / raw) On Wed, 30 Jul 2003 11:31:03 +0000 (UTC), Lutz Donnerhacke <lutz@iks-jena.de> wrote: >I'm using an Limited_Controlled type as an 'out' parameter of a procedure. >While programming this procedure in question, I wonder how to Finalize the >object given as argument to the 'out' parameter. > >------------------------------------------------------------------------ >with Ada.Finalization; > >package t1 is > type Test is new Ada.Finalization.Limited_Controlled with record > a : Character; > end record; > procedure Initialize(o : in out Test); > procedure Finalize(o : in out Test); > procedure Copy(to : out Test; from : Test); >end t1; >------------------------------------------------------------------------ >with t1; >use t1; > >procedure t is > a, b, c : Test; >begin > Copy(a, b); > Copy(a, c); >end t; [...] >This results in: > Initializing 0 > Initializing 1 > Initializing 2 > Copying 1 to 3 > Copying 2 to 4 > Finalizing 2 > Finalizing 1 > Finalizing 4 > >Clearly, the variable 0 and 3 are never finalized. How implement I this >correctly (without refering to the rosen trick). 1. Why do you think that it is incorrect? Copy does not destruct the target, so why should it call Finalize? 2. But if you still want something like that, then make Copy class-wide: type Test is new Ada.Finalization.Limited_Controlled with ... procedure Destruct (This : in out Test); procedure Construct (To : in out Test; From : Test); procedure Copy (To : in out Test'Class; From : Test'Class) is begin Destruct (To); Construct (To, From); end Copy; procedure Finalize (This : in out Test) is begin Destruct (Test); -- Carefully here, when overriding Finalize! -- You will probably need a flag preventing -- multiple calls to Destruct upon finalization. -- Alternatively, you could refrain from calling parent's -- Finalize, but then you should ensure that -- Destruct does everything needed. end Finalize; Beware, true multiple dispatch is not supported in Ada. So if you want to copy objects of different types you have to simulate MD. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 12:22 ` Dmitry A. Kazakov @ 2003-07-30 12:32 ` Lutz Donnerhacke 2003-07-30 14:24 ` Dmitry A. Kazakov 0 siblings, 1 reply; 25+ messages in thread From: Lutz Donnerhacke @ 2003-07-30 12:32 UTC (permalink / raw) * Dmitry A Kazakov wrote: > On Wed, 30 Jul 2003 11:31:03 +0000 (UTC), Lutz Donnerhacke >> procedure Copy(to : out Test; from : Test); >> >>Clearly, the variable 0 and 3 are never finalized. How implement I this >>correctly (without refering to the rosen trick). > > 1. Why do you think that it is incorrect? Copy does not destruct the > target, so why should it call Finalize? In my implementation, the type Test contains an array_access, I have to deallocate, before assigning a new value. I can not deallocate this access variable, because the procedure Free (unchecked_deallocate) requires an 'in out' Parameter. But I only have an 'out' paramter. So I can't read it, before the first write. In short: The former contents (despite discriminates) of an 'out' parameter are not available inside the procedure. So the former contents are not finalizable inside this procedure. > procedure Copy (To : in out Test'Class; From : Test'Class) is > begin > Destruct (To); > Construct (To, From); > end Copy; Fine, but try this with the prototype: procedure Copy (To : out Test'Class; From : Test'Class); > Beware, true multiple dispatch is not supported in Ada. So if you want > to copy objects of different types you have to simulate MD. Wrong answer. Not every problem is MI related. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 12:32 ` Lutz Donnerhacke @ 2003-07-30 14:24 ` Dmitry A. Kazakov 2003-07-30 14:25 ` Lutz Donnerhacke 0 siblings, 1 reply; 25+ messages in thread From: Dmitry A. Kazakov @ 2003-07-30 14:24 UTC (permalink / raw) On Wed, 30 Jul 2003 12:32:17 +0000 (UTC), Lutz Donnerhacke <lutz@iks-jena.de> wrote: >* Dmitry A Kazakov wrote: >> On Wed, 30 Jul 2003 11:31:03 +0000 (UTC), Lutz Donnerhacke >>> procedure Copy(to : out Test; from : Test); >>> >>>Clearly, the variable 0 and 3 are never finalized. How implement I this >>>correctly (without refering to the rosen trick). >> >> 1. Why do you think that it is incorrect? Copy does not destruct the >> target, so why should it call Finalize? > >In my implementation, the type Test contains an array_access, I have to >deallocate, before assigning a new value. I can not deallocate this access >variable, because the procedure Free (unchecked_deallocate) requires an >'in out' Parameter. But I only have an 'out' paramter. So I can't read it, >before the first write. You can in Ada 95. >In short: The former contents (despite discriminates) of an 'out' parameter >are not available inside the procedure. So the former contents are not >finalizable inside this procedure. > >> procedure Copy (To : in out Test'Class; From : Test'Class) is >> begin >> Destruct (To); >> Construct (To, From); >> end Copy; > >Fine, but try this with the prototype: > procedure Copy (To : out Test'Class; From : Test'Class); This compiles with GNAT: ----------------------- with Ada.Finalization; package A is type Int_Ptr is access Integer; type Test is new Ada.Finalization.Limited_Controlled with record Ptr : Int_Ptr; end record; procedure Destruct (To : in out Test); procedure Construct (To : in out Test; From : Test); procedure Copy (To : out Test'Class; From : Test'Class); end A; --------------------- with Ada.Finalization; with Ada.Unchecked_Deallocation; package body A is procedure Free is new Ada.Unchecked_Deallocation (Integer, Int_Ptr); procedure Destruct (To : in out Test) is begin Free (To.Ptr); end Destruct; procedure Construct (To : in out Test; From : Test) is begin To.Ptr := From.Ptr; end Construct; procedure Copy (To : out Test'Class; From : Test'Class) is begin Destruct (To); Construct (To, From); end Copy; end A; >> Beware, true multiple dispatch is not supported in Ada. So if you want >> to copy objects of different types you have to simulate MD. > >Wrong answer. Not every problem is MI related. MD /= MI. Multiple dispatch is when there are many controlling arguments of different tags. Assignment / copy is a case. You have source and target, and sometimes you want assign: X : Local_String; Y : Remote_String; Copy (Y, X); -- Constraint_Error --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 14:24 ` Dmitry A. Kazakov @ 2003-07-30 14:25 ` Lutz Donnerhacke 2003-07-30 14:48 ` Dmitry A. Kazakov ` (2 more replies) 0 siblings, 3 replies; 25+ messages in thread From: Lutz Donnerhacke @ 2003-07-30 14:25 UTC (permalink / raw) * Dmitry A Kazakov wrote: > On Wed, 30 Jul 2003 12:32:17 +0000 (UTC), Lutz Donnerhacke >>In my implementation, the type Test contains an array_access, I have to >>deallocate, before assigning a new value. I can not deallocate this access >>variable, because the procedure Free (unchecked_deallocate) requires an >>'in out' Parameter. But I only have an 'out' paramter. So I can't read it, >>before the first write. > > You can in Ada 95. Oops. Why? This is a clear data flow error, which should be avoided. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 14:25 ` Lutz Donnerhacke @ 2003-07-30 14:48 ` Dmitry A. Kazakov 2003-07-30 15:15 ` Lutz Donnerhacke 2003-07-30 15:01 ` Vinzent Hoefler 2003-07-30 15:52 ` Lutz Donnerhacke 2 siblings, 1 reply; 25+ messages in thread From: Dmitry A. Kazakov @ 2003-07-30 14:48 UTC (permalink / raw) On Wed, 30 Jul 2003 14:25:46 +0000 (UTC), Lutz Donnerhacke <lutz@iks-jena.de> wrote: >* Dmitry A Kazakov wrote: >> On Wed, 30 Jul 2003 12:32:17 +0000 (UTC), Lutz Donnerhacke >>>In my implementation, the type Test contains an array_access, I have to >>>deallocate, before assigning a new value. I can not deallocate this access >>>variable, because the procedure Free (unchecked_deallocate) requires an >>>'in out' Parameter. But I only have an 'out' paramter. So I can't read it, >>>before the first write. >> >> You can in Ada 95. > >Oops. Why? This is a clear data flow error, which should be avoided. It is an interesting question. What could be alternatives 1. to leave "out" parameters uninitialized. This is bad. 2. to disallow reading from them, but then how to get discriminants? 2.a. to disallow reading before first write except for discriminants, constraints and type tag. Well, how many pages would it take to consistently describe something like that in ARM? (:-)) Add here is some run-time checks burden. 2.b. return statement for "out" procedure Foo (X : out String; Y : Some'Class) is begin return ( X => "Any text", Y => Create_Some ); end Foo; looks awful, and after all how to implement unconstrained "out" parameters? --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 14:48 ` Dmitry A. Kazakov @ 2003-07-30 15:15 ` Lutz Donnerhacke 2003-07-31 10:26 ` Dmitry A. Kazakov 0 siblings, 1 reply; 25+ messages in thread From: Lutz Donnerhacke @ 2003-07-30 15:15 UTC (permalink / raw) * Dmitry A Kazakov wrote: > On Wed, 30 Jul 2003 14:25:46 +0000 (UTC), Lutz Donnerhacke >>* Dmitry A Kazakov wrote: >>> On Wed, 30 Jul 2003 12:32:17 +0000 (UTC), Lutz Donnerhacke >>>>In my implementation, the type Test contains an array_access, I have to >>>>deallocate, before assigning a new value. I can not deallocate this access >>>>variable, because the procedure Free (unchecked_deallocate) requires an >>>>'in out' Parameter. But I only have an 'out' paramter. So I can't read it, >>>>before the first write. >>> >>> You can in Ada 95. >> >>Oops. Why? This is a clear data flow error, which should be avoided. > > It is an interesting question. What could be alternatives > > 1. to leave "out" parameters uninitialized. This is bad. This is the most common implementation on most types. (most = unless you define an Initialize procedure, default component data, or provide initialization data) > 2. to disallow reading from them, but then how to get discriminants? Discriminants of 'out' types have mode 'in'. Always. > 2.a. to disallow reading before first write except for discriminants, > constraints and type tag. Discriminants, ... can't be written on 'out' types. > 2.b. return statement for "out" > > procedure Foo (X : out String; Y : Some'Class) is > begin > return > ( X => "Any text", > Y => Create_Some > ); > end Foo; No! 3) Finalize the current data of the 'limited out' parameter. Adjust the assigned data of the 'unlimited out' paramter after return. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 15:15 ` Lutz Donnerhacke @ 2003-07-31 10:26 ` Dmitry A. Kazakov 2003-07-31 10:54 ` Lutz Donnerhacke 0 siblings, 1 reply; 25+ messages in thread From: Dmitry A. Kazakov @ 2003-07-31 10:26 UTC (permalink / raw) On Wed, 30 Jul 2003 15:15:09 +0000 (UTC), Lutz Donnerhacke <lutz@iks-jena.de> wrote: >* Dmitry A Kazakov wrote: >> On Wed, 30 Jul 2003 14:25:46 +0000 (UTC), Lutz Donnerhacke >>>* Dmitry A Kazakov wrote: >>>> On Wed, 30 Jul 2003 12:32:17 +0000 (UTC), Lutz Donnerhacke >>>>>In my implementation, the type Test contains an array_access, I have to >>>>>deallocate, before assigning a new value. I can not deallocate this access >>>>>variable, because the procedure Free (unchecked_deallocate) requires an >>>>>'in out' Parameter. But I only have an 'out' paramter. So I can't read it, >>>>>before the first write. >>>> >>>> You can in Ada 95. >>> >>>Oops. Why? This is a clear data flow error, which should be avoided. >> >> It is an interesting question. What could be alternatives >> >> 1. to leave "out" parameters uninitialized. This is bad. > >This is the most common implementation on most types. (most = unless you >define an Initialize procedure, default component data, or provide >initialization data) No they all are initialized, but probably with a garbage. (:-)) A really uninialized object is *(cast *) malloc (). Fortunately, we have no this evil in Ada. >> 2. to disallow reading from them, but then how to get discriminants? > >Discriminants of 'out' types have mode 'in'. Always. Not always: type A (I : Integer := 10) is null record; procedure Foo (X : out A) is begin X := (I => 5); -- Change the discriminant end Foo; >3) Finalize the current data of the 'limited out' parameter. > Adjust the assigned data of the 'unlimited out' paramter after return. It would be inconsistent. Adjust is called after a raw copy is made, your subprogram uses a valid type interface instead. And you better don't do it after Finalize [+ other destructors] were called. Consider a task object as a member of your limited type. What you actually describe is a copy constructor, not a subroutine. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-31 10:26 ` Dmitry A. Kazakov @ 2003-07-31 10:54 ` Lutz Donnerhacke 2003-07-31 11:50 ` Dmitry A. Kazakov 2003-07-31 17:51 ` Randy Brukardt 0 siblings, 2 replies; 25+ messages in thread From: Lutz Donnerhacke @ 2003-07-31 10:54 UTC (permalink / raw) * Dmitry A Kazakov wrote: >>> 1. to leave "out" parameters uninitialized. This is bad. >> >>This is the most common implementation on most types. (most = unless you >>define an Initialize procedure, default component data, or provide >>initialization data) > > No they all are initialized, but probably with a garbage. (:-)) It's not that funny, if you need those data to manage ressources. Managing data which is possibly garbage is very hard. >>Discriminants of 'out' types have mode 'in'. Always. > > Not always: > > type A (I : Integer := 10) is null record; Ok. >>3) Finalize the current data of the 'limited out' parameter. >> Adjust the assigned data of the 'unlimited out' paramter after return. > > It would be inconsistent. Adjust is called after a raw copy is made, > your subprogram uses a valid type interface instead. And you better > don't do it after Finalize [+ other destructors] were called. Consider > a task object as a member of your limited type. I still do not get it completely. ------------------------------------------------------------------------ with Ada.Finalization; package t1 is type Char_Access is access Character; type Test is new Ada.Finalization.Limited_Controlled with record a : Char_Access; end record; procedure Initialize(o : in out Test); procedure Finalize(o : in out Test); procedure Set(o1, o2 : out Test; i : Test); end t1; ------------------------------------------------------------------------ with Ada.Text_IO; with System.Storage_Elements, System.Address_To_Access_Conversions; with Unchecked_Deallocation; use Ada.Text_IO; package body t1 is procedure Debug (msg : String; p : Char_Access) is use System.Storage_Elements; package Convert is new System.Address_To_Access_Conversions(Character); begin Put_Line(msg & Integer_Address'Image(To_Integer( Convert.To_Address(Convert.Object_Pointer(p)))) & '(' & p.all & ')'); end Debug; global : Character := '0'; procedure Initialize(o : in out Test) is begin o.a := new Character'(global); Debug("Initializing", o.a); global := Character'Succ(global); end Initialize; procedure Free is new Unchecked_Deallocation(Character, Char_Access); procedure Finalize(o : in out Test) is begin Debug("Finalizing ", o.a); Free(o.a); end Finalize; procedure Set(o1, o2 : out Test; i : Test) is begin Debug("Setting from", i.a); Debug("Setting o1 ", o1.a); Debug("Setting o2 ", o2.a); Finalize(o1); Finalize(o2); o1.a := new Character'(global); Debug("Setting to1 ", o1.a); global := Character'Succ(global); o2.a := new Character'(i.a.all); Debug("Setting to2 ", o2.a); end Set; end t1; ------------------------------------------------------------------------ with t1; use t1; procedure t is a, b : Test; begin Set(a, a, b); end t; ------------------------------------------------------------------------ Results in: Initializing 134630800(0) Initializing 134630816(1) Setting from 134630816(1) Setting o1 134630800(0) Setting o2 134630800(0) Finalizing 134630800(0) raised PROGRAM_ERROR : t1.adb:14 Finalizing 134630816(1) I'am mad? ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-31 10:54 ` Lutz Donnerhacke @ 2003-07-31 11:50 ` Dmitry A. Kazakov 2003-07-31 12:19 ` Lutz Donnerhacke 2003-07-31 17:51 ` Randy Brukardt 1 sibling, 1 reply; 25+ messages in thread From: Dmitry A. Kazakov @ 2003-07-31 11:50 UTC (permalink / raw) On Thu, 31 Jul 2003 10:54:44 +0000 (UTC), Lutz Donnerhacke <lutz@iks-jena.de> wrote: >* Dmitry A Kazakov wrote: >>>> 1. to leave "out" parameters uninitialized. This is bad. >>> >>>This is the most common implementation on most types. (most = unless you >>>define an Initialize procedure, default component data, or provide >>>initialization data) >> >> No they all are initialized, but probably with a garbage. (:-)) > >It's not that funny, if you need those data to manage ressources. Managing >data which is possibly garbage is very hard. The point is that formally the constructor exists, though does nothing. So everything is initialized. You might be just unsatisfied with the way of a particular initialization is done. Well, I was alone against chorus chanting "we do not need user constructors for all types". Wellcome in club. (:-)) >>>3) Finalize the current data of the 'limited out' parameter. >>> Adjust the assigned data of the 'unlimited out' paramter after return. >> >> It would be inconsistent. Adjust is called after a raw copy is made, >> your subprogram uses a valid type interface instead. And you better >> don't do it after Finalize [+ other destructors] were called. Consider >> a task object as a member of your limited type. > >I still do not get it completely. > >------------------------------------------------------------------------ >with Ada.Finalization; > >package t1 is > type Char_Access is access Character; > type Test is new Ada.Finalization.Limited_Controlled with record > a : Char_Access; > end record; > procedure Initialize(o : in out Test); > procedure Finalize(o : in out Test); > procedure Set(o1, o2 : out Test; i : Test); >end t1; >------------------------------------------------------------------------ >with Ada.Text_IO; >with System.Storage_Elements, System.Address_To_Access_Conversions; >with Unchecked_Deallocation; >use Ada.Text_IO; > >package body t1 is > procedure Debug (msg : String; p : Char_Access) is > use System.Storage_Elements; > package Convert is new System.Address_To_Access_Conversions(Character); > begin > Put_Line(msg & > Integer_Address'Image(To_Integer( > Convert.To_Address(Convert.Object_Pointer(p)))) & > '(' & p.all & ')'); > end Debug; > > global : Character := '0'; > > procedure Initialize(o : in out Test) is > begin > o.a := new Character'(global); > Debug("Initializing", o.a); > global := Character'Succ(global); > end Initialize; > > procedure Free is new Unchecked_Deallocation(Character, Char_Access); > procedure Finalize(o : in out Test) is > begin > Debug("Finalizing ", o.a); > Free(o.a); > end Finalize; > > procedure Set(o1, o2 : out Test; i : Test) is > begin > Debug("Setting from", i.a); > Debug("Setting o1 ", o1.a); > Debug("Setting o2 ", o2.a); > Finalize(o1); > Finalize(o2); > > o1.a := new Character'(global); > Debug("Setting to1 ", o1.a); > global := Character'Succ(global); > > o2.a := new Character'(i.a.all); > Debug("Setting to2 ", o2.a); > end Set; >end t1; >------------------------------------------------------------------------ >with t1; >use t1; > >procedure t is > a, b : Test; >begin > Set(a, a, b); >end t; >------------------------------------------------------------------------ > >Results in: >Initializing 134630800(0) >Initializing 134630816(1) >Setting from 134630816(1) >Setting o1 134630800(0) >Setting o2 134630800(0) >Finalizing 134630800(0) >raised PROGRAM_ERROR : t1.adb:14 >Finalizing 134630816(1) > >I'am mad? Sort of, if you are calling Finalize from a normal subprogram! (:-)) As for error, you call Set (a, a, b); which finalizes a twice! It is a language design fault that a destructor can be called explicitly. Your example shows why. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-31 11:50 ` Dmitry A. Kazakov @ 2003-07-31 12:19 ` Lutz Donnerhacke 2003-07-31 13:15 ` Dmitry A. Kazakov 0 siblings, 1 reply; 25+ messages in thread From: Lutz Donnerhacke @ 2003-07-31 12:19 UTC (permalink / raw) * Dmitry A Kazakov wrote: > On Thu, 31 Jul 2003 10:54:44 +0000 (UTC), Lutz Donnerhacke >> procedure Set(o1, o2 : out Test; i : Test) is >> begin >> Debug("Setting from", i.a); >> Debug("Setting o1 ", o1.a); >> Debug("Setting o2 ", o2.a); >> Finalize(o1); >> Finalize(o2); >> >> o1.a := new Character'(global); >> Debug("Setting to1 ", o1.a); >> global := Character'Succ(global); >> >> o2.a := new Character'(i.a.all); >> Debug("Setting to2 ", o2.a); >> end Set; > > Sort of, if you are calling Finalize from a normal subprogram! (:-)) > As for error, you call Set (a, a, b); which finalizes a twice! It is a > language design fault that a destructor can be called explicitly. Your > example shows why. Changing the "Finalize" calls to "Free" causes the same effect. So the main point is: How to manage resources correctly? procedure Set(o1, o2 : out Test; i : Test) is begin Debug("Setting from", i.a); if o1'Address /= o2'Address then Debug("Setting o1 ", o1.a); Free(o1.a); o1.a := new Character'(global); Debug("Setting to1 ", o1.a); global := Character'Succ(global); end if; Debug("Setting o2 ", o2.a); Free(o2.a); o2.a := new Character'(i.a.all); Debug("Setting to2 ", o2.a); end Set; GNA! ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-31 12:19 ` Lutz Donnerhacke @ 2003-07-31 13:15 ` Dmitry A. Kazakov 0 siblings, 0 replies; 25+ messages in thread From: Dmitry A. Kazakov @ 2003-07-31 13:15 UTC (permalink / raw) On Thu, 31 Jul 2003 12:19:17 +0000 (UTC), Lutz Donnerhacke <lutz@iks-jena.de> wrote: >* Dmitry A Kazakov wrote: >> On Thu, 31 Jul 2003 10:54:44 +0000 (UTC), Lutz Donnerhacke >>> procedure Set(o1, o2 : out Test; i : Test) is >>> begin >>> Debug("Setting from", i.a); >>> Debug("Setting o1 ", o1.a); >>> Debug("Setting o2 ", o2.a); >>> Finalize(o1); >>> Finalize(o2); >>> >>> o1.a := new Character'(global); >>> Debug("Setting to1 ", o1.a); >>> global := Character'Succ(global); >>> >>> o2.a := new Character'(i.a.all); >>> Debug("Setting to2 ", o2.a); >>> end Set; >> >> Sort of, if you are calling Finalize from a normal subprogram! (:-)) >> As for error, you call Set (a, a, b); which finalizes a twice! It is a >> language design fault that a destructor can be called explicitly. Your >> example shows why. > >Changing the "Finalize" calls to "Free" causes the same effect. >So the main point is: How to manage resources correctly? What do you mean? Aliasing problem or assignment of limited types? Anyway what should not be confused is that assignment, copy constructor, copy procedure, all are very different things. > procedure Set(o1, o2 : out Test; i : Test) is > begin > Debug("Setting from", i.a); > if o1'Address /= o2'Address then > Debug("Setting o1 ", o1.a); > Free(o1.a); > > o1.a := new Character'(global); > Debug("Setting to1 ", o1.a); > global := Character'Succ(global); > end if; > > Debug("Setting o2 ", o2.a); > Free(o2.a); > o2.a := new Character'(i.a.all); > Debug("Setting to2 ", o2.a); > end Set; > >GNA! This should work. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-31 10:54 ` Lutz Donnerhacke 2003-07-31 11:50 ` Dmitry A. Kazakov @ 2003-07-31 17:51 ` Randy Brukardt 1 sibling, 0 replies; 25+ messages in thread From: Randy Brukardt @ 2003-07-31 17:51 UTC (permalink / raw) "Lutz Donnerhacke" <lutz@iks-jena.de> wrote in message news:slrnbihtb3.2j7.lutz@taranis.iks-jena.de... ... > Results in: > Initializing 134630800(0) > Initializing 134630816(1) > Setting from 134630816(1) > Setting o1 134630800(0) > Setting o2 134630800(0) > Finalizing 134630800(0) > raised PROGRAM_ERROR : t1.adb:14 > Finalizing 134630816(1) > > I'am mad? Yes. :-) Finalize routines always have to be written to work on an already finalized object. There are variety of ways for extra Finalize calls to occur even without any explicit ones. So your Finalize needs to be something like: procedure Finalize(o : in out Test) is begin if o.a /= null then Debug("Finalizing ", o.a); Free(o.a); -- else already finalized. end if; end Finalize; Otherwise, you're freeing an already freed object. This is discussed in the AARM: http://www.adaic.org/standards/95aarm/html/AA-7-6-1.html See the note at paragraph 24 and the following discussion. Randy. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 14:25 ` Lutz Donnerhacke 2003-07-30 14:48 ` Dmitry A. Kazakov @ 2003-07-30 15:01 ` Vinzent Hoefler 2003-07-30 15:16 ` Lutz Donnerhacke 2003-07-30 15:52 ` Lutz Donnerhacke 2 siblings, 1 reply; 25+ messages in thread From: Vinzent Hoefler @ 2003-07-30 15:01 UTC (permalink / raw) Lutz Donnerhacke wrote: >* Dmitry A Kazakov wrote: > [reading "out"-Parameters] >> You can in Ada 95. > >Oops. Why? Convinience. Sometimes it avoids the temporary copy that would be needed in Ada83. See the example below. >This is a clear data flow error, Not if you have updated the object inside the procedure before reading it, consider this: | procedure Set_Timer_Limits (Input_Frequency : in Frequency; | Limit : in Min_Max; | Timer : out TxParm; | In_Range : out Boolean) is | begin | -- here the Timer object is not yet initialized, reading | -- would be a data flow error | Timer.Min := Clamp8254 (Input_Frequency / Limit.Max); | Timer.Max := Clamp8254 (Input_Frequency / Limit.Min); | | -- but here we can simply read it without data flow error | -- or the need for a temporary copy | In_Range := ((Input_Frequency / Timer.Max) > Limit.Min) and | ((Input_Frequency / Timer.Min) < Limit.Max); | end Set_Timer_Limits; Vinzent. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 15:01 ` Vinzent Hoefler @ 2003-07-30 15:16 ` Lutz Donnerhacke 0 siblings, 0 replies; 25+ messages in thread From: Lutz Donnerhacke @ 2003-07-30 15:16 UTC (permalink / raw) * Vinzent Hoefler wrote: > Lutz Donnerhacke wrote: >>* Dmitry A Kazakov wrote: > [reading "out"-Parameters] >>> You can in Ada 95. >> >>Oops. Why? > > Convinience. Sometimes it avoids the temporary copy that would be > needed in Ada83. See the example below. > >>This is a clear data flow error, > > Not if you have updated the object inside the procedure before reading > it, consider this: > >| procedure Set_Timer_Limits (Input_Frequency : in Frequency; >| Limit : in Min_Max; >| Timer : out TxParm; >| In_Range : out Boolean) is >| begin >| -- here the Timer object is not yet initialized, reading >| -- would be a data flow error Got it. This is the place, where a finalization like access have to be done. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 14:25 ` Lutz Donnerhacke 2003-07-30 14:48 ` Dmitry A. Kazakov 2003-07-30 15:01 ` Vinzent Hoefler @ 2003-07-30 15:52 ` Lutz Donnerhacke 2003-07-30 19:30 ` Randy Brukardt 2 siblings, 1 reply; 25+ messages in thread From: Lutz Donnerhacke @ 2003-07-30 15:52 UTC (permalink / raw) * Lutz Donnerhacke wrote: > * Dmitry A Kazakov wrote: >> On Wed, 30 Jul 2003 12:32:17 +0000 (UTC), Lutz Donnerhacke >>>In my implementation, the type Test contains an array_access, I have to >>>deallocate, before assigning a new value. I can not deallocate this access >>>variable, because the procedure Free (unchecked_deallocate) requires an >>>'in out' Parameter. But I only have an 'out' paramter. So I can't read it, >>>before the first write. >> >> You can in Ada 95. > > Oops. Why? This is a clear data flow error, which should be avoided. To stress this point even more. The approbriate counterpart using assignment statments and controlled types result in: ------------------------------------------------------------------------ with Ada.Finalization; package t1 is type Char_Access is access Character; type Test is new Ada.Finalization.Controlled with record a : Char_Access; end record; procedure Initialize(o : in out Test); procedure Finalize(o : in out Test); procedure Adjust(o : in out Test); end t1; ------------------------------------------------------------------------ with t1; use t1; procedure t is a, b, c : Test; begin a := b; a := c; end t; ------------------------------------------------------------------------ with Ada.Text_IO; with System.Storage_Elements, System.Address_To_Access_Conversions; with Unchecked_Deallocation; use Ada.Text_IO; package body t1 is procedure Debug (msg : String; p : Char_Access) is use System.Storage_Elements; package Convert is new System.Address_To_Access_Conversions(Character); begin Put_Line(msg & Integer_Address'Image(To_Integer( Convert.To_Address(Convert.Object_Pointer(p)))) & '(' & p.all & ')'); end Debug; global : Character := '0'; procedure Initialize(o : in out Test) is begin o.a := new Character'(global); Debug("Initializing", o.a); global := Character'Succ(global); end Initialize; procedure Finalize(o : in out Test) is procedure Free is new Unchecked_Deallocation(Character, Char_Access); begin Debug("Finalizing", o.a); Free(o.a); end Finalize; procedure Adjust(o : in out Test) is procedure Free is new Unchecked_Deallocation(Character, Char_Access); tmp : Char_Access := new Character'(' '); -- occupy some memory begin Debug("Adjusting from", o.a); o.a := new Character'(o.a.all); Debug("Adjusting to ", o.a); Free(tmp); end Adjust; end t1; ------------------------------------------------------------------------ Results in: Initializing 134630032(0) Initializing 134630048(1) Initializing 134630064(2) Finalizing 134630032(0) Adjusting from 134630048(1) Adjusting to 134630080(1) Finalizing 134630080(1) Adjusting from 134630064(2) Adjusting to 134630032(2) Finalizing 134630064(2) Finalizing 134630048(1) Finalizing 134630032(2) Despite the upthead argument "there are only three instances, so finalizing them suffice", here are also only three instances, which are finalized before assigment. Trying it with an 'out' parameter procedure Set(o : out Test) is begin Debug("Setting from", o.a); o.a := new Character'(global); Debug("Setting to ", o.a); global := Character'Succ(global); end Set; [...] with t1; use t1; procedure t is a, b, c : Test; begin a := b; a := c; Set(a); Set(a); end t; ------------------------------------------------------------------------ gives: Initializing 134630064(0) Initializing 134630080(1) Initializing 134630096(2) Finalizing 134630064(0) Adjusting from 134630080(1) Adjusting to 134630112(1) Finalizing 134630112(1) Adjusting from 134630096(2) Adjusting to 134630064(2) Setting from 134630064(2) Setting to 134630112(3) Setting from 134630112(3) Setting to 134630128(4) Finalizing 134630096(2) Finalizing 134630080(1) Finalizing 134630128(4) which is clearly wrong in the same way. So the only result of this can be: Do not provide 'out' Parameters to controlled types in the same library unit. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 15:52 ` Lutz Donnerhacke @ 2003-07-30 19:30 ` Randy Brukardt 2003-07-31 7:43 ` Lutz Donnerhacke 0 siblings, 1 reply; 25+ messages in thread From: Randy Brukardt @ 2003-07-30 19:30 UTC (permalink / raw) "Lutz Donnerhacke" <lutz@iks-jena.de> wrote in message news:slrnbifqdp.o6.lutz@taranis.iks-jena.de... ... > which is clearly wrong in the same way. Of course. "in out" and "out" parameters for tagged types (and most other types as well) are equivalent. Consider the lack of an "in" to be a comment to the caller, not to the author of the subprogram. There is never an "uninitialized" tagged object. Some of the components may not be initialized (esp. if the type isn't controlled), but the object as a whole is initialized. If it wasn't, the tag wouldn't be set, which would make even membership operations impossible. > So the only result of this can be: Do not provide 'out' Parameters to > controlled types in the same library unit. No, just realize that "out" is the same as "in out" as far as the implementation of a routine is concerned. But it still can provide useful information to the caller. Randy. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 19:30 ` Randy Brukardt @ 2003-07-31 7:43 ` Lutz Donnerhacke 0 siblings, 0 replies; 25+ messages in thread From: Lutz Donnerhacke @ 2003-07-31 7:43 UTC (permalink / raw) * Randy Brukardt wrote: > "Lutz Donnerhacke" <lutz@iks-jena.de> wrote in message >> which is clearly wrong in the same way. > > Of course. "in out" and "out" parameters for tagged types (and most other > types as well) are equivalent. Consider the lack of an "in" to be a comment > to the caller, not to the author of the subprogram. I thought a call "xxx(my)" to "procedure xxx (a : out Test)" is very similar to "my := xxx", if a "function xxx return Test" exists. This idea is wrong. > not be initialized (esp. if the type isn't controlled), but the object as a > whole is initialized. If it wasn't, the tag wouldn't be set, which would > make even membership operations impossible. Ack for discriminants, tags, etc. Nack for private data. So the consequence is: If you pass a controlled type as an 'out' paramenter in the type defining library unit, provide sufficient initialization for all private data, otherwise you can't distiguish uninitalized garbage from real data. >> So the only result of this can be: Do not provide 'out' Parameters to >> controlled types in the same library unit. > > No, just realize that "out" is the same as "in out" as far as the > implementation of a routine is concerned. But it still can provide useful > information to the caller. I'm going to see this, but I'm still confused. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 11:31 Limited_Controlled types as 'out' arguments Lutz Donnerhacke 2003-07-30 12:22 ` Dmitry A. Kazakov @ 2003-07-30 12:31 ` Matthew Heaney 2003-07-30 12:57 ` Lutz Donnerhacke 2003-07-30 12:37 ` Martin Dowie 2 siblings, 1 reply; 25+ messages in thread From: Matthew Heaney @ 2003-07-30 12:31 UTC (permalink / raw) "Lutz Donnerhacke" <lutz@iks-jena.de> wrote in message news:slrnbifb3k.o6.lutz@taranis.iks-jena.de... > I'm using an Limited_Controlled type as an 'out' parameter of a procedure. > While programming this procedure in question, I wonder how to Finalize the > object given as argument to the 'out' parameter. Controlled types, like all tagged types, are passed by reference. Three objects (a, b, c) are Initialize'd , and the same three objects are Finalize'd. Which objects do you think aren't being finalized? ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 12:31 ` Matthew Heaney @ 2003-07-30 12:57 ` Lutz Donnerhacke 2003-07-30 13:47 ` Martin Dowie 2003-07-30 17:06 ` Matthew Heaney 0 siblings, 2 replies; 25+ messages in thread From: Lutz Donnerhacke @ 2003-07-30 12:57 UTC (permalink / raw) * Matthew Heaney wrote: > Controlled types, like all tagged types, are passed by reference. 'out' Parameters can't be read. > Three objects (a, b, c) are Initialize'd , and the same three objects are > Finalize'd. > > Which objects do you think aren't being finalized? Extended example: ------------------------------------------------------------------------ with Ada.Finalization; package t1 is type Char_Access is access Character; type Test is new Ada.Finalization.Limited_Controlled with record a : Char_Access; end record; procedure Initialize(o : in out Test); procedure Finalize(o : in out Test); procedure Copy(to : out Test; from : Test); end t1; ------------------------------------------------------------------------ with t1; use t1; procedure t is a, b, c : Test; begin Copy(a, b); Copy(a, c); end t; ------------------------------------------------------------------------ with Ada.Text_IO; with System.Storage_Elements, System.Address_To_Access_Conversions; with Unchecked_Deallocation; use Ada.Text_IO; package body t1 is procedure Debug (msg : String; p : Char_Access) is use System.Storage_Elements; package Convert is new System.Address_To_Access_Conversions(Character); begin Put_Line(msg & Integer_Address'Image(To_Integer( Convert.To_Address(Convert.Object_Pointer(p)))) & '(' & p.all & ')'); end Debug; global : Character := '0'; procedure Initialize(o : in out Test) is begin o.a := new Character'(global); Debug("Initializing", o.a); global := Character'Succ(global); end Initialize; procedure Finalize(o : in out Test) is procedure Free is new Unchecked_Deallocation(Character, Char_Access); begin Debug("Finalizing", o.a); Free(o.a); end Finalize; procedure Copy(to : out Test; from : Test) is begin to.a := new Character'(global); Debug("Copying from", from.a); Debug("Copying to ", to.a); global := Character'Succ(global); end Copy; end t1; ------------------------------------------------------------------------ Results in a beautiful memory leak: Initializing 134630832(0) Initializing 134630848(1) Initializing 134630864(2) Copying from 134630848(1) Copying to 134630880(3) Copying from 134630864(2) Copying to 134630896(4) Finalizing 134630864(2) Finalizing 134630848(1) Finalizing 134630896(4) 134630832 and 134630880 are never freed. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 12:57 ` Lutz Donnerhacke @ 2003-07-30 13:47 ` Martin Dowie 2003-07-30 17:06 ` Matthew Heaney 1 sibling, 0 replies; 25+ messages in thread From: Martin Dowie @ 2003-07-30 13:47 UTC (permalink / raw) > procedure Debug (msg : String; p : Char_Access) is Also, to demonstrate that it is the same 3 variables, don't use the address of something inside, use the 'Address of the actual variables. procedure Debug (Msg : String; P : System.Address) is ... Debug("Initializing", O'Address); and then everything can be seen to be ok. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 12:57 ` Lutz Donnerhacke 2003-07-30 13:47 ` Martin Dowie @ 2003-07-30 17:06 ` Matthew Heaney 1 sibling, 0 replies; 25+ messages in thread From: Matthew Heaney @ 2003-07-30 17:06 UTC (permalink / raw) Lutz Donnerhacke <lutz@iks-jena.de> wrote in message news:<slrnbifg5p.o6.lutz@taranis.iks-jena.de>... > * Matthew Heaney wrote: > > Controlled types, like all tagged types, are passed by reference. > > 'out' Parameters can't be read. This statement is false. Controlled initialization for the object passed as the out parameter of the call has already occured at the time of elaboration of the object, which is prior to the call. Controlled finalization of the object occurs when the scope containing the declaration ends. The issue of invokation of controlled operations is orthogonal to the issue of whether the object is passed as an out parameter. There is nothing wrong with your original example. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 11:31 Limited_Controlled types as 'out' arguments Lutz Donnerhacke 2003-07-30 12:22 ` Dmitry A. Kazakov 2003-07-30 12:31 ` Matthew Heaney @ 2003-07-30 12:37 ` Martin Dowie 2003-07-30 12:59 ` Lutz Donnerhacke 2 siblings, 1 reply; 25+ messages in thread From: Martin Dowie @ 2003-07-30 12:37 UTC (permalink / raw) "Lutz Donnerhacke" <lutz@iks-jena.de> wrote in message news:slrnbifb3k.o6.lutz@taranis.iks-jena.de... > I'm using an Limited_Controlled type as an 'out' parameter of a procedure. [snip] > procedure Copy(to : out Test; from : Test) is > begin > to.a := global; > Put_Line("Copying " & from.a & " to " & to.a); > global := Character'Succ(global); > end Copy; Shouldn't this actually copy something out of 'from'? ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 12:37 ` Martin Dowie @ 2003-07-30 12:59 ` Lutz Donnerhacke 2003-07-30 13:41 ` Martin Dowie 0 siblings, 1 reply; 25+ messages in thread From: Lutz Donnerhacke @ 2003-07-30 12:59 UTC (permalink / raw) * Martin Dowie wrote: > "Lutz Donnerhacke" <lutz@iks-jena.de> wrote in message >> procedure Copy(to : out Test; from : Test) is >> begin >> to.a := global; >> Put_Line("Copying " & from.a & " to " & to.a); >> global := Character'Succ(global); >> end Copy; > > Shouldn't this actually copy something out of 'from'? For examples you cut your real world problem until it's small. Yes, it's sufficent to call 'procedure example(a : out Test)'. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Limited_Controlled types as 'out' arguments 2003-07-30 12:59 ` Lutz Donnerhacke @ 2003-07-30 13:41 ` Martin Dowie 0 siblings, 0 replies; 25+ messages in thread From: Martin Dowie @ 2003-07-30 13:41 UTC (permalink / raw) "Lutz Donnerhacke" <lutz@iks-jena.de> wrote in message news:slrnbifg8q.o6.lutz@taranis.iks-jena.de... > * Martin Dowie wrote: > > Shouldn't this actually copy something out of 'from'? > > For examples you cut your real world problem until it's small. > Yes, it's sufficent to call 'procedure example(a : out Test)'. Sorry, it just looked like confusion over 'where' the '0'&'3' values had gone - and they had simply been overwitten. But of course there a memory leak - it's here: procedure Copy(to : out Test; from : Test) is begin to.a := new Character'(global); ---- <<<<<<<<< You've over writen what "to.a" did point to with something else. Perhaps you meant "to.a.all := Global;" ^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2003-07-31 17:51 UTC | newest] Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2003-07-30 11:31 Limited_Controlled types as 'out' arguments Lutz Donnerhacke 2003-07-30 12:22 ` Dmitry A. Kazakov 2003-07-30 12:32 ` Lutz Donnerhacke 2003-07-30 14:24 ` Dmitry A. Kazakov 2003-07-30 14:25 ` Lutz Donnerhacke 2003-07-30 14:48 ` Dmitry A. Kazakov 2003-07-30 15:15 ` Lutz Donnerhacke 2003-07-31 10:26 ` Dmitry A. Kazakov 2003-07-31 10:54 ` Lutz Donnerhacke 2003-07-31 11:50 ` Dmitry A. Kazakov 2003-07-31 12:19 ` Lutz Donnerhacke 2003-07-31 13:15 ` Dmitry A. Kazakov 2003-07-31 17:51 ` Randy Brukardt 2003-07-30 15:01 ` Vinzent Hoefler 2003-07-30 15:16 ` Lutz Donnerhacke 2003-07-30 15:52 ` Lutz Donnerhacke 2003-07-30 19:30 ` Randy Brukardt 2003-07-31 7:43 ` Lutz Donnerhacke 2003-07-30 12:31 ` Matthew Heaney 2003-07-30 12:57 ` Lutz Donnerhacke 2003-07-30 13:47 ` Martin Dowie 2003-07-30 17:06 ` Matthew Heaney 2003-07-30 12:37 ` Martin Dowie 2003-07-30 12:59 ` Lutz Donnerhacke 2003-07-30 13:41 ` Martin Dowie
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox