comp.lang.ada
 help / color / mirror / Atom feed
* Trying to understand Ada.Finalization.Controlled assignment mechanics.
@ 2014-09-23  0:43 Jeremiah
  2014-09-23  1:17 ` Jeffrey Carter
  0 siblings, 1 reply; 9+ messages in thread
From: Jeremiah @ 2014-09-23  0:43 UTC (permalink / raw)


My understanding of assignment of a child of Ada.Finalization.Controlled is that if you do the following:

A := B;  -- A and B are derived from Ada.Finalization.Controlled

That the following occurs:
Finalize(A);
Copy B into A;
Adjust(B);

Is this correct?

I've been learning/relearning Ada lately, so I have been mainly making programs to get a better understanding of the mechanics of Ada.  In order to understand assignment, I made a quick tester class.  It isn't very useful nor is it meant to be, but it highlights something that I don't understand.  

test_class2.ads
----------------------------------
with Ada.Finalization;

package test_class2 is
   
   type access_type is access Integer;

   type test is new Ada.Finalization.Controlled with record
      ref : access_type := null;
   end record;
   
   function Make(a : access_type) return test;
   overriding procedure Adjust(self : in out test);
   overriding procedure Finalize(self : in out test);

end test_class2;



test_class2.adb
--------------------------
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Deallocation;

package body test_class2 is

   function Make(a : access_type) return test is
   begin
      return (Ada.Finalization.Controlled with ref => a);
   end Make;
   
   overriding procedure Adjust(self : in out test) is
   begin
      Put_Line("Adjusting");
      self.ref := null;
   end Adjust;
   
   overriding procedure Finalize(self : in out test) is
      procedure Free is new Ada.Unchecked_Deallocation(Integer, access_type);
   begin
      Put("Finalizing");
      if(self.ref /= null) then
         Put("  (FREED)");
         Free(self.ref);
      end if;
      New_Line;
   end Finalize;
   
end test_class2;



Main.adb
--------------------------
with Ada.Text_IO;  use Ada.Text_IO;
with test_class2;

procedure Main is
   tester : test_class2.test := test_class2.Make(new Integer'(45));
begin
   Put_Line("Hello World");
end Main;

The output I am seeing doesn't make sense to me:
Adjusting
Finalizing  (FREED)
Adjusting
Finalizing
Hello World
Finalizing

I wouldn't expect the Freeing of memory to happen until after Hello World when tester goes out of scope.  I also thought that Finalize happens before Adjust, but Adjust looks like is happening first.  I am compiling and running this on GNAT GPL for windows if that makes a difference.  I don't have a different hardware platform to test on.

Can anyone explain to me why the "freeing" of memory happens prior to Hello World and whey Adjusting happens before Finalization?  I figure I have something fundamental that I am missing.

Thanks!


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Trying to understand Ada.Finalization.Controlled assignment mechanics.
  2014-09-23  0:43 Trying to understand Ada.Finalization.Controlled assignment mechanics Jeremiah
@ 2014-09-23  1:17 ` Jeffrey Carter
  2014-09-23 16:08   ` Jeremiah
  0 siblings, 1 reply; 9+ messages in thread
From: Jeffrey Carter @ 2014-09-23  1:17 UTC (permalink / raw)


On 09/22/2014 05:43 PM, Jeremiah wrote:
> My understanding of assignment of a child of Ada.Finalization.Controlled is that if you do the following:
> 
> A := B;  -- A and B are derived from Ada.Finalization.Controlled
> 
> That the following occurs:
> Finalize(A);
> Copy B into A;
> Adjust(B);
> 
> Is this correct?

Not necessarily. This is an assignment statement. ARM 7.6(17) says

'For an assignment_statement, after the name and expression have been evaluated,
and any conversion (including constraint checking) has been done, an anonymous
object is created, and the value is assigned into it; that is, the assignment
operation is applied. (Assignment includes value adjustment.) The target of the
assignment_statement is then finalized. The value of the anonymous object is
then assigned into the target of the assignment_statement. Finally, the
anonymous object is finalized. As explained below, the implementation may
eliminate the intermediate anonymous object, so this description subsumes the
one given in 5.2, “Assignment Statements”.'

So it could be

Create C (the anonymous object);
Copy B into C;
Adjust (C);
Finalize (A);
Copy C into A;
Adjust (A);
Finalize (C);

If the anonymous object is optimized away, then it becomes your sequence.

>    tester : test_class2.test := test_class2.Make(new Integer'(45));
>
> The output I am seeing doesn't make sense to me:
> Adjusting
> Finalizing  (FREED)
> Adjusting
> Finalizing
> Hello World
> Finalizing

Your test example is complicated by the use of the function and the aggregate
inside it.  Someone with a better understanding of GNAT's handling of controlled
objects should probably comment on this. But it might be a good idea to start
with a simpler test case, involving no initialization, functions, aggregates, or
access types, and then complicate it step by step.

ARM 7.6(17.1/3) says

'When a function call or aggregate is used to initialize an object, the result
of the function call or aggregate is an anonymous object, which is assigned into
the newly-created object.'

My guess is that there are both an aggregate object and function return object.
The aggregate object is copied into the function return object (FRO), the FRO is
adjusted, and the aggregate object is finalized. The the FRO is copied into
Tester, Tester is adjusted, and the FRO is finalized. The body of the main
procedure is then executed, and Tester is finalized. But I could be way off.

http://www.adaic.org/resources/add_content/standards/12rm/html/RM-7-6.html

-- 
Jeff Carter
"Blessed are they who convert their neighbors'
oxen, for they shall inhibit their girth."
Monty Python's Life of Brian
83


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Trying to understand Ada.Finalization.Controlled assignment mechanics.
  2014-09-23  1:17 ` Jeffrey Carter
@ 2014-09-23 16:08   ` Jeremiah
  2014-09-23 16:23     ` Adam Beneschan
                       ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Jeremiah @ 2014-09-23 16:08 UTC (permalink / raw)


On Monday, September 22, 2014 9:17:18 PM UTC-4, Jeffrey Carter wrote:
> On 09/22/2014 05:43 PM, Jeremiah wrote:
> 
> >    tester : test_class2.test := test_class2.Make(new Integer'(45));
> 
> >
> 
> > The output I am seeing doesn't make sense to me:
> 
> > Adjusting
> 
> > Finalizing  (FREED)
> 
> > Adjusting
> 
> > Finalizing
> 
> > Hello World
> 
> > Finalizing
> 
> 
> 
> Your test example is complicated by the use of the function and the aggregate
> 
> inside it.  Someone with a better understanding of GNAT's handling of controlled
> 
> objects should probably comment on this. But it might be a good idea to start
> 
> with a simpler test case, involving no initialization, functions, aggregates, or
> 
> access types, and then complicate it step by step.
> 
> 
> 
> ARM 7.6(17.1/3) says
> 
> 
> 
> 'When a function call or aggregate is used to initialize an object, the result
> 
> of the function call or aggregate is an anonymous object, which is assigned into
> 
> the newly-created object.'
> 
> 
> 
> My guess is that there are both an aggregate object and function return object.
> 
> The aggregate object is copied into the function return object (FRO), the FRO is
> 
> adjusted, and the aggregate object is finalized. The the FRO is copied into
> 
> Tester, Tester is adjusted, and the FRO is finalized. The body of the main
> 
> procedure is then executed, and Tester is finalized. But I could be way off.
> 
> 
> 
> http://www.adaic.org/resources/add_content/standards/12rm/html/RM-7-6.html
> 

It does complicate things, and in the simpler case (using a Set procedure), it does highlight a misunderstanding of mine.  I incorrectly assumed Adjust would occur on B, when based on your response and rereading the RM section a few times, Adjust occurs on A instead.  

Am I understanding that correctly?  If so, then this would explain what I am seeing as I am setting the target to null and not nulling the previous object (which is the reverse of what I previously understood).

TLDR version (barring the actual complexities you noted above):
I previously thought:
A := B
Finalize(A)
copying B into A
Adjust(B)

But in reality it is closer to:
Finalize(A)
copying B into A
Adjust(A)

Again, not taking into account the complexities of FRO's and Anonymous Objects.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Trying to understand Ada.Finalization.Controlled assignment mechanics.
  2014-09-23 16:08   ` Jeremiah
@ 2014-09-23 16:23     ` Adam Beneschan
  2014-09-23 17:39       ` Simon Wright
  2014-09-23 17:50     ` Jeffrey Carter
  2014-09-23 19:19     ` Robert A Duff
  2 siblings, 1 reply; 9+ messages in thread
From: Adam Beneschan @ 2014-09-23 16:23 UTC (permalink / raw)


On Tuesday, September 23, 2014 9:08:39 AM UTC-7, Jeremiah wrote:

> Am I understanding that correctly?  If so, then this would explain what I am seeing as I am setting the target to null and not nulling the previous object (which is the reverse of what I previously understood).
> 
> TLDR version (barring the actual complexities you noted above):
> I previously thought:
> A := B
> Finalize(A)
> copying B into A
> Adjust(B)
> 
> But in reality it is closer to:
> Finalize(A)
> copying B into A
> Adjust(A)
> 
> Again, not taking into account the complexities of FRO's and Anonymous Objects.

Yes, you've got it right.  If you say "A := B;", B is not modified at all.  B could be a constant, in fact, and it could be located in read-only memory.  (An Adjust(B) call would try to modify B.)

Although Adjust can be used for a number of things, one of the most common cases is to make a copy of pointed-to data.  Say the record type has a field Data that is an access type to some array.  Say you don't want two records of the same type pointing to the exact same array, but instead you want to make a copy of the array when you create a new object of the type.  That's where Adjust comes in.

When you say A := B, the program will copy B into A, which means they temporarily have an access (pointer) to the same data.  The Adjust procedure would then allocate a new array, make a copy of it, and leave A's Data pointing to the new array.  (It doesn't modify B's data pointer at all, and you wouldn't want to, even if B weren't constant.)  The Finalize procedure would deallocate the array.  Assuming that the record type is private so that outside packages can't modify the Data pointer directly, this will ensure that each record points to its own copy of the array, and that there will not be any dangling pointers to deallocated arrays, unless the outside code does something underhanded like Unchecked_Conversion or something.

                                 -- Adam


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Trying to understand Ada.Finalization.Controlled assignment mechanics.
  2014-09-23 16:23     ` Adam Beneschan
@ 2014-09-23 17:39       ` Simon Wright
  0 siblings, 0 replies; 9+ messages in thread
From: Simon Wright @ 2014-09-23 17:39 UTC (permalink / raw)


Adam Beneschan <adambeneschan@gmail.com> writes:

> The Adjust
> procedure would then allocate a new array, make a copy of it, and
> leave A's Data pointing to the new array

.. allocate a new array, copy B's data into it, and leave ...


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Trying to understand Ada.Finalization.Controlled assignment mechanics.
  2014-09-23 16:08   ` Jeremiah
  2014-09-23 16:23     ` Adam Beneschan
@ 2014-09-23 17:50     ` Jeffrey Carter
  2014-09-23 19:19     ` Robert A Duff
  2 siblings, 0 replies; 9+ messages in thread
From: Jeffrey Carter @ 2014-09-23 17:50 UTC (permalink / raw)


On 09/23/2014 09:08 AM, Jeremiah wrote:
> 
> I previously thought:
> A := B
> Finalize(A)
> copying B into A
> Adjust(B)

I must have misread that. Adjust is always called on the target of assignment (A
in this case). As Beneschan pointed out, B could be constant.

> But in reality it is closer to:
> Finalize(A)
> copying B into A
> Adjust(A)

In the case where the anonymous temporary is optimized away, this is what happens.

-- 
Jeff Carter
"All citizens will be required to change their underwear
every half hour. Underwear will be worn on the outside,
so we can check."
Bananas
29


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Trying to understand Ada.Finalization.Controlled assignment mechanics.
  2014-09-23 16:08   ` Jeremiah
  2014-09-23 16:23     ` Adam Beneschan
  2014-09-23 17:50     ` Jeffrey Carter
@ 2014-09-23 19:19     ` Robert A Duff
  2014-09-23 21:59       ` Jeremiah
  2 siblings, 1 reply; 9+ messages in thread
From: Robert A Duff @ 2014-09-23 19:19 UTC (permalink / raw)


Jeremiah <jeremiah.breeden@gmail.com> writes:

> Finalize(A)
> copying B into A
> Adjust(A)

Right.

It might help to look at some examples.  Maybe take a look at the
GNAT implementation of Ada.Containers.Vectors, in a-convec.ad* .

- Bob


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Trying to understand Ada.Finalization.Controlled assignment mechanics.
  2014-09-23 19:19     ` Robert A Duff
@ 2014-09-23 21:59       ` Jeremiah
  2014-09-24 10:59         ` AdaMagica
  0 siblings, 1 reply; 9+ messages in thread
From: Jeremiah @ 2014-09-23 21:59 UTC (permalink / raw)


Thanks everyone for the responses

On Tuesday, September 23, 2014 3:19:52 PM UTC-4, Robert A Duff wrote:
> Jeremiah  writes:
> 
> 
> 
> > Finalize(A)
> 
> > copying B into A
> 
> > Adjust(A)
> 
> 
> 
> Right.
> 
> 
> 
> It might help to look at some examples.  Maybe take a look at the
> 
> GNAT implementation of Ada.Containers.Vectors, in a-convec.ad* .
> 
> 
> 
> - Bob

Thank you, I will.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Trying to understand Ada.Finalization.Controlled assignment mechanics.
  2014-09-23 21:59       ` Jeremiah
@ 2014-09-24 10:59         ` AdaMagica
  0 siblings, 0 replies; 9+ messages in thread
From: AdaMagica @ 2014-09-24 10:59 UTC (permalink / raw)


On Tuesday, September 23, 2014 11:59:29 PM UTC+2, Jeremiah wrote:
> Thanks everyone for the responses

For a very detailed analysis of controlledness, you are invited to look at my page

http://www.christ-usch-grein.homepage.t-online.de/AdaMagica/Secretive.html


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-09-24 10:59 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-23  0:43 Trying to understand Ada.Finalization.Controlled assignment mechanics Jeremiah
2014-09-23  1:17 ` Jeffrey Carter
2014-09-23 16:08   ` Jeremiah
2014-09-23 16:23     ` Adam Beneschan
2014-09-23 17:39       ` Simon Wright
2014-09-23 17:50     ` Jeffrey Carter
2014-09-23 19:19     ` Robert A Duff
2014-09-23 21:59       ` Jeremiah
2014-09-24 10:59         ` AdaMagica

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