comp.lang.ada
 help / color / mirror / Atom feed
* Question about library-level functions
@ 2012-12-15  3:38 ytomino
  2012-12-15  9:47 ` AdaMagica
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: ytomino @ 2012-12-15  3:38 UTC (permalink / raw)


Hello.

What's the difference between a library-level(top-level?) function(A) and a function(B) in a library-level package?

with Something;
function A return access T; -- returns new allocated value

with Something;
package P is
   function B return access T; -- same as above
end P;

I had thought these are same.
But, returned value from A seems that's finalized inside A.
B is not.

Does the master of a library-level function happen to exist inside itself?




My test case is below:

---- %< ----

with Ada.Finalization;
package lifetime is
   type T is limited private;
   function Create return T;
private
   type T is limited new Ada.Finalization.Limited_Controlled with null record;
   overriding procedure Finalize (Object : in out T);
end lifetime;

with Ada.Text_IO;
with System.Address_Image;
package body lifetime is
   procedure Finalize (Object : in out T) is
   begin
      Ada.Text_IO.Put_Line ("Finalize (" & System.Address_Image (Object'Address) & ")");
   end Finalize;
   function Create return T is
   begin
      return Result : T := (Ada.Finalization.Limited_Controlled with null record) do
         Ada.Text_IO.Put_Line ("Initialize (" & System.Address_Image (Result'Address) & ")");
      end return;
   end Create;
end lifetime;

with lifetime;
function alloc return access lifetime.T;

function alloc return access lifetime.T is
begin
   return new lifetime.T'(lifetime.Create);
   -- lifetime.Finalize may be called here
end alloc;

with Ada.Text_IO;
with lifetime;
with alloc;
procedure main is
begin
   Ada.Text_IO.Put_Line ("before");
   declare
      type A is access all lifetime.T;
      P : A := A(alloc);
   begin
      -- P.all may be already finalized!!!
      Ada.Text_IO.Put_Line ("lifetime");
   end;
   Ada.Text_IO.Put_Line ("after");
end main;

---- >% ----

% gnatmake -gnat2012 main.adb && ./main
before
Initialize (0000000100100090)
Finalize (0000000100100090) <- !!!!
lifetime
after

When I tried to move 'alloc' to inside of any package, the calling lifetime.Finalize in 'alloc' would not be invoked. It's natural.



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

* Re: Question about library-level functions
  2012-12-15  3:38 Question about library-level functions ytomino
@ 2012-12-15  9:47 ` AdaMagica
  2012-12-15 10:50   ` ytomino
  2012-12-15 15:23 ` sbelmont700
  2012-12-16  9:43 ` Simon Wright
  2 siblings, 1 reply; 17+ messages in thread
From: AdaMagica @ 2012-12-15  9:47 UTC (permalink / raw)


> What's the difference between a library-level(top-level?) function(A) and
> a function(B) in a library-level package?

Hm, I think the lifetime of the returned object is in both cases the same.

> with Ada.Text_IO;
> with lifetime;
> with alloc;
> procedure main is
> begin
>    Ada.Text_IO.Put_Line ("before");
>    declare
>       type A is access all lifetime.T;
>       P : A := A(alloc);
Finalize may not be called in Alloc, since the object must be created in place
(it's limited - there cannot be an intermediate object as in the unlimited
case).
>    begin
>       -- P.all may be already finalized!!!
I guess that, since P is unused, the compiler optimizes the sequence of calls
and finalizes P first.
>       Ada.Text_IO.Put_Line ("lifetime");
Finalize must at the latest be called here before the block is left.
>    end;
>    Ada.Text_IO.Put_Line ("after");
> end main;
>
> % gnatmake -gnat2012 main.adb && ./main
>
> before
> Initialize (0000000100100090)
> Finalize (0000000100100090) <- !!!!
> lifetime
> after



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

* Re: Question about library-level functions
  2012-12-15  9:47 ` AdaMagica
@ 2012-12-15 10:50   ` ytomino
  2012-12-15 11:38     ` AdaMagica
  0 siblings, 1 reply; 17+ messages in thread
From: ytomino @ 2012-12-15 10:50 UTC (permalink / raw)


On Saturday, December 15, 2012 6:47:10 PM UTC+9, AdaMagica wrote:

> I guess that, since P is unused, the compiler optimizes the sequence of calls 
> and finalizes P first. 

hurm...So, I tried to change it to do explicit free P.

---- %< ----

with Ada.Text_IO;
with Ada.Unchecked_Deallocation;
with lifetime;
with alloc;
procedure main is
begin
   Ada.Text_IO.Put_Line ("before");
   declare
      type A is access all lifetime.T;
      procedure Free is new Ada.Unchecked_Deallocation (lifetime.T, A);
      P : A := A(alloc);
   begin
      Ada.Text_IO.Put_Line ("lifetime");
      Free (P);
   end;
   Ada.Text_IO.Put_Line ("after");
end main;

---- %> ----

As a result, lifetime.Finalize was called twice.

% ./main
before
Initialize (0000000100100090)
Finalize (0000000100100090)
lifetime
Finalize (0000000100100090)
after

> Finalize may not be called in Alloc,  

Surely, lifetime.Finalize may be called in 'Alloc'.
The backtrace of gdb is:

#0  lifetime__finalize__2 (object=) at lifetime.adb:7
#1  0x0000000100001a9c in lifetime__tFD () at lifetime.adb:4
#2  0x000000010000da39 in system__finalization_masters__finalize (master=) at s-finmas.adb:241
#3  0x00000001000026d8 in _ada_alloc () at alloc.adb:5
#4  0x00000001000028f2 in _ada_main () at main.adb:11

> since the object must be created in place
> (it's limited - there cannot be an intermediate object as in the unlimited 
> case). 

lifetime.T is limited. However, an access value of it is not limited.

Perhaps AARM 7.6.1 says the anonymous access type belongs to innermost master.
The master is usually in the package and lets objects live long time.
I imagine, if a function is library-level, there is no place which it puts the master, so the master is inside of the function...???



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

* Re: Question about library-level functions
  2012-12-15 10:50   ` ytomino
@ 2012-12-15 11:38     ` AdaMagica
  2012-12-17 19:49       ` Adam Beneschan
  0 siblings, 1 reply; 17+ messages in thread
From: AdaMagica @ 2012-12-15 11:38 UTC (permalink / raw)


> As a result, lifetime.Finalize was called twice.
> % ./main
> before
> Initialize (0000000100100090)
> Finalize (0000000100100090)
> lifetime
> Finalize (0000000100100090)
> after

 Hm, I'm no lnaguage lawer, but this looks wrong to me.

> > Finalize may not be called in Alloc,  
> Surely, lifetime.Finalize may be called in 'Alloc'.
>
> The backtrace of gdb is:
>
> #0  lifetime__finalize__2 (object=) at lifetime.adb:7
> #1  0x0000000100001a9c in lifetime__tFD () at lifetime.adb:4
> #2  0x000000010000da39 in system__finalization_masters__finalize (master=) at s-finmas.adb:241
> #3  0x00000001000026d8 in _ada_alloc () at alloc.adb:5
> #4  0x00000001000028f2 in _ada_main () at main.adb:11

Don't know what's happening here...

> > since the object must be created in place
> > (it's limited - there cannot be an intermediate object as in the unlimited 
> > case). 
>
> lifetime.T is limited. However, an access value of it is not limited.

Irrelevant, since it's an object of type T that's finalized here at the end of the lifetime of the corresponding access type.

> Perhaps AARM 7.6.1 says the anonymous access type belongs to innermost master.
> The master is usually in the package and lets objects live long time.
> I imagine, if a function is library-level, there is no place which it
> puts the master, so the master is inside of the function...???

Hm, the master of type A is the access block.

But I'm not sure who the master is of the anonymous access type declared with function Alloc. It should be the environment task, just as that is ultimately the master of any library unit (be it a package or a subprogram).

In effect, I do not really understand what is happening here...



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

* Re: Question about library-level functions
  2012-12-15  3:38 Question about library-level functions ytomino
  2012-12-15  9:47 ` AdaMagica
@ 2012-12-15 15:23 ` sbelmont700
  2012-12-16  6:09   ` ytomino
  2012-12-16  9:43 ` Simon Wright
  2 siblings, 1 reply; 17+ messages in thread
From: sbelmont700 @ 2012-12-15 15:23 UTC (permalink / raw)


On Friday, December 14, 2012 10:38:20 PM UTC-5, ytomino wrote:
> 
>    function Create return T is
> 
>    begin
> 
>       return Result : T := (Ada.Finalization.Limited_Controlled with null record) do
> 
>          Ada.Text_IO.Put_Line ("Initialize (" & System.Address_Image (Result'Address) & ")");
> 
>       end return;
> 
>    end Create;


FWIW, I have run into several occasions where GNAT 2012 extended return statements randomly try to finalize objects erroneously, though usually I end up with a program error ('finalize raised exception').  My feeling is that if you change the above to:

    function Create return T is
    begin

      return (Ada.Finalization.Limited_Controlled with null record);

    end Create;

your problem could mysteriously vanish.

-sb



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

* Re: Question about library-level functions
  2012-12-15 15:23 ` sbelmont700
@ 2012-12-16  6:09   ` ytomino
  0 siblings, 0 replies; 17+ messages in thread
From: ytomino @ 2012-12-16  6:09 UTC (permalink / raw)


On Sunday, December 16, 2012 12:23:46 AM UTC+9, sbelm...@gmail.com wrote:
> FWIW, I have run into several occasions where GNAT 2012 extended return statements randomly try to finalize objects erroneously, though usually I end up with a program error ('finalize raised exception').  My feeling is that if you change the above to:
> 
>     function Create return T is
>     begin
>       return (Ada.Finalization.Limited_Controlled with null record);
>     end Create;
> 
> your problem could mysteriously vanish.
> 
> -sb

Thanks. But, regrettable, the results are the same...



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

* Re: Question about library-level functions
  2012-12-15  3:38 Question about library-level functions ytomino
  2012-12-15  9:47 ` AdaMagica
  2012-12-15 15:23 ` sbelmont700
@ 2012-12-16  9:43 ` Simon Wright
  2012-12-16 10:21   ` AdaMagica
  2012-12-16 13:34   ` ytomino
  2 siblings, 2 replies; 17+ messages in thread
From: Simon Wright @ 2012-12-16  9:43 UTC (permalink / raw)


ytomino <aghia05@gmail.com> writes:

> function alloc return access lifetime.T is
> begin
>    return new lifetime.T'(lifetime.Create);
>    -- lifetime.Finalize may be called here
> end alloc;

I think that what's happening is that a (limited) temporary lifetime.T
object is created (on the heap, or perhaps the secondary stack). Its
access is taken for the return value, and then (because we're leaving
the scope) it gets finalized.

Whether this is what's meant to happen I don't know!



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

* Re: Question about library-level functions
  2012-12-16  9:43 ` Simon Wright
@ 2012-12-16 10:21   ` AdaMagica
  2012-12-16 13:07     ` ytomino
                       ` (2 more replies)
  2012-12-16 13:34   ` ytomino
  1 sibling, 3 replies; 17+ messages in thread
From: AdaMagica @ 2012-12-16 10:21 UTC (permalink / raw)


On Sunday, December 16, 2012 10:43:41 AM UTC+1, Simon Wright wrote:
> ytomino writes:
>
> > function alloc return access lifetime.T is
> > begin
> >    return new lifetime.T'(lifetime.Create);
> >    -- lifetime.Finalize may be called here
> > end alloc;
>
> I think that what's happening is that a (limited) temporary lifetime.T
> object is created (on the heap, or perhaps the secondary stack). Its
> access is taken for the return value, and then (because we're leaving
> the scope) it gets finalized.

Looks like so, but IMHO this is illegal. A limited object must be created in-place. (Of course an implementation can do as it likes and create first a temporary object, then copy it to the final one and finalize the temporary *if* the result is as though it was created in-place. But here, it seems like the same object is finalized twice.)

What may be temporary and copied it the access value and not the accessed object. It's standard to create an object via an access and return the latter - the object must not be finalized, of course.

Creating via anonymous access is evil - how can ou ever deallocate it? This should be verboten by the language.



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

* Re: Question about library-level functions
  2012-12-16 10:21   ` AdaMagica
@ 2012-12-16 13:07     ` ytomino
  2012-12-16 18:31     ` Simon Wright
  2012-12-18  0:07     ` Randy Brukardt
  2 siblings, 0 replies; 17+ messages in thread
From: ytomino @ 2012-12-16 13:07 UTC (permalink / raw)


On Sunday, December 16, 2012 7:21:23 PM UTC+9, AdaMagica wrote:
> Creating via anonymous access is evil - how can ou ever deallocate it? This should be verboten by the language.

I do'nt intent to deallocate it at my code.

However, I think, it's able to be deallocated by a named access type as long as these types use same storage pool shown by pragma Default_Storage_Pool.



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

* Re: Question about library-level functions
  2012-12-16  9:43 ` Simon Wright
  2012-12-16 10:21   ` AdaMagica
@ 2012-12-16 13:34   ` ytomino
  2012-12-16 15:54     ` AdaMagica
  1 sibling, 1 reply; 17+ messages in thread
From: ytomino @ 2012-12-16 13:34 UTC (permalink / raw)


On Sunday, December 16, 2012 6:43:41 PM UTC+9, Simon Wright wrote:
> I think that what's happening is that a (limited) temporary lifetime.T
> object is created (on the heap, or perhaps the secondary stack). Its
> access is taken for the return value, and then (because we're leaving
> the scope) it gets finalized.

I think so too.
For that reason, I imagine that the master of the top-level function exists inside of oneself.

> Whether this is what's meant to happen I don't know!

I want to throw my spoon!



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

* Re: Question about library-level functions
  2012-12-16 13:34   ` ytomino
@ 2012-12-16 15:54     ` AdaMagica
  2012-12-18  0:09       ` Randy Brukardt
  0 siblings, 1 reply; 17+ messages in thread
From: AdaMagica @ 2012-12-16 15:54 UTC (permalink / raw)


> For that reason, I imagine that the master of the top-level
> function exists inside of oneself.

No, it's the environment task. And the finalization is wrong at this place.



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

* Re: Question about library-level functions
  2012-12-16 10:21   ` AdaMagica
  2012-12-16 13:07     ` ytomino
@ 2012-12-16 18:31     ` Simon Wright
  2012-12-18  3:18       ` ytomino
  2012-12-18  0:07     ` Randy Brukardt
  2 siblings, 1 reply; 17+ messages in thread
From: Simon Wright @ 2012-12-16 18:31 UTC (permalink / raw)


AdaMagica <christ-usch.grein@t-online.de> writes:

> On Sunday, December 16, 2012 10:43:41 AM UTC+1, Simon Wright wrote:
>> ytomino writes:
>>
>> > function alloc return access lifetime.T is
>> > begin
>> >    return new lifetime.T'(lifetime.Create);
>> >    -- lifetime.Finalize may be called here
>> > end alloc;
>>
>> I think that what's happening is that a (limited) temporary lifetime.T
>> object is created (on the heap, or perhaps the secondary stack). Its
>> access is taken for the return value, and then (because we're leaving
>> the scope) it gets finalized.
>
> Looks like so, but IMHO this is illegal. A limited object must be
> created in-place. (Of course an implementation can do as it likes and
> create first a temporary object, then copy it to the final one and
> finalize the temporary *if* the result is as though it was created
> in-place. But here, it seems like the same object is finalized twice.)
>
> What may be temporary and copied it the access value and not the
> accessed object. It's standard to create an object via an access and
> return the latter - the object must not be finalized, of course.
>
> Creating via anonymous access is evil - how can ou ever deallocate it?
> This should be verboten by the language.

OP is quite right that the code behaves properly if alloc() is declared
in a package, and misbehaves when alloc() is declared at library
level. I think this has to be a bug.

Who's going to report it?



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

* Re: Question about library-level functions
  2012-12-15 11:38     ` AdaMagica
@ 2012-12-17 19:49       ` Adam Beneschan
  2012-12-18  2:26         ` ytomino
  0 siblings, 1 reply; 17+ messages in thread
From: Adam Beneschan @ 2012-12-17 19:49 UTC (permalink / raw)


On Saturday, December 15, 2012 3:38:44 AM UTC-8, AdaMagica wrote:

> But I'm not sure who the master is of the anonymous access type declared with function Alloc. It should be the environment task, just as that is ultimately the master of any library unit (be it a package or a subprogram).

There were some rule changes in Ada 2012 in 3.10.2 and 7.6.1, and I haven't yet studied them all.  But my initial reading is that since the anonymous access function result is converted to a named access type A, then the object that gets allocated should be finalized when A disappears, i.e. at the end of the block that declares A.  I could easily be wrong.

                        -- Adam



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

* Re: Question about library-level functions
  2012-12-16 10:21   ` AdaMagica
  2012-12-16 13:07     ` ytomino
  2012-12-16 18:31     ` Simon Wright
@ 2012-12-18  0:07     ` Randy Brukardt
  2 siblings, 0 replies; 17+ messages in thread
From: Randy Brukardt @ 2012-12-18  0:07 UTC (permalink / raw)


"AdaMagica" <christ-usch.grein@t-online.de> wrote in message 
news:a7a82a85-48e4-4ded-b090-06f62bd3b0b6@googlegroups.com...
...
>Creating via anonymous access is evil - how can ou ever deallocate it? This 
>should be verboten by the language.

A few too many words here: "anonymous access is evil" would have been 
enough. (At least for access-to-object.) The rules for accessibility (and 
thus finalization) are impossible to understand and typically require 
dynamic checks. Dynamic accessibility checks are surely evil, as they add 
overhead, create a "tripping hazard" (some uses are OK, others fail at 
runtime, which is not indicated by the specification), and only detect a 
minority of problems (most real uses have to resort to 'Unchecked_Access 
anyway).

These types were a mistake in Ada 95 and expanding their use compounded the 
mistake. Too bad it wasn't obvious from the beginning.

Vis-a-vis your original comment -- Ada 2012 at least gives restrictions that 
let users self-impose what the language does not:
   pragma Restrictions (No_Anonymous_Allocators); -- H.4(8.1/3)
   pragma Restrictions (No_Coextensions); -- H.4(8.2/3)
   pragma Restrictions (No_Access_Parameter_Allocators); -- H.4(8.3/3)

Can't make these the default for compatibility reasons, of course.

                                            Randy.





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

* Re: Question about library-level functions
  2012-12-16 15:54     ` AdaMagica
@ 2012-12-18  0:09       ` Randy Brukardt
  0 siblings, 0 replies; 17+ messages in thread
From: Randy Brukardt @ 2012-12-18  0:09 UTC (permalink / raw)


"AdaMagica" <christ-usch.grein@t-online.de> wrote in message 
news:de6feb16-f72f-431d-81d8-6db38b36735c@googlegroups.com...
>> For that reason, I imagine that the master of the top-level
>> function exists inside of oneself.
>
> No, it's the environment task. And the finalization is wrong at this 
> place.

Right. Finalization depends only on the call of a function, it has nothing 
to do with where it is declared. So this is clearly a bug. (Precisely what 
is supposed to happen I am not going to guess [or research], but it can't be 
different.)

                           Randy.





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

* Re: Question about library-level functions
  2012-12-17 19:49       ` Adam Beneschan
@ 2012-12-18  2:26         ` ytomino
  0 siblings, 0 replies; 17+ messages in thread
From: ytomino @ 2012-12-18  2:26 UTC (permalink / raw)


On Tuesday, December 18, 2012 4:49:41 AM UTC+9, Adam Beneschan wrote:
> There were some rule changes in Ada 2012 in 3.10.2 and 7.6.1, and I haven't yet studied them all.  But my initial reading is that since the anonymous access function result is converted to a named access type A, then the object that gets allocated should be finalized when A disappears, i.e. at the end of the block that declares A.  I could easily be wrong.
> 
> 
> 
>                         -- Adam

I'm reading that you pointed, now.

RM 3.10.2 (10.3/3) says "If the result is of an anonymous access type and is the operand of an explicit conversion, the master is that of the target type of the conversion;". The rule is just applicable to this case. This statement is added when Ada 2012.
Or, In Ada 2005 RM, (10/2) says "The accessibility level of an aggregate or the result of a function call (or equivalent use of an operator) that is used (in its entirety) to directly initialize part of an object is that of the object being initialized. In other contexts, the accessibility level of an aggregate or the result of a function call is that of the innermost master that evaluates the aggregate or function call. ". 
The innermost master or *function call* is probably in the block of type A.

I came to be sure that my understanding was wrong and it's a bug of the compiler.
Thanks.



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

* Re: Question about library-level functions
  2012-12-16 18:31     ` Simon Wright
@ 2012-12-18  3:18       ` ytomino
  0 siblings, 0 replies; 17+ messages in thread
From: ytomino @ 2012-12-18  3:18 UTC (permalink / raw)


On Monday, December 17, 2012 3:31:08 AM UTC+9, Simon Wright wrote:
> Who's going to report it?

OK, I reported it.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55725



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

end of thread, other threads:[~2012-12-18  3:18 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-12-15  3:38 Question about library-level functions ytomino
2012-12-15  9:47 ` AdaMagica
2012-12-15 10:50   ` ytomino
2012-12-15 11:38     ` AdaMagica
2012-12-17 19:49       ` Adam Beneschan
2012-12-18  2:26         ` ytomino
2012-12-15 15:23 ` sbelmont700
2012-12-16  6:09   ` ytomino
2012-12-16  9:43 ` Simon Wright
2012-12-16 10:21   ` AdaMagica
2012-12-16 13:07     ` ytomino
2012-12-16 18:31     ` Simon Wright
2012-12-18  3:18       ` ytomino
2012-12-18  0:07     ` Randy Brukardt
2012-12-16 13:34   ` ytomino
2012-12-16 15:54     ` AdaMagica
2012-12-18  0:09       ` Randy Brukardt

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