Unexpected order of __finalize

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Unexpected order of __finalize

Max McGuire
I've run into some unexpected behavior with the __finalize method. Specifically if my class has members that are also classes, the __finalize methods for the members are getting called before the __finalize method for the owner.

Here's a simple example:

class 'B'

function B:__finalize()
    print("B:__finalize\n")
end

class 'A'

function A:__init()
    self.b = B()
end

function A:__finalize()
    print("A:__finalize\n")
end

local a = A()
a = nil

collectgarbage("collect")

The output from this program is:

B:__finalize
A:__finalize

This is the opposite behavior that you would get from a C++ program and is problematic, especially if B is actually a class implemented in C++ and you tried to access b during the __finalize method for A.

Is this by design or am I missing something?

Thanks,

Max

--
Technical Director
Unknown Worlds Entertainment
http://www.unknownworlds.com

------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Unexpected order of __finalize

Max McGuire
For what it's worth, I was able to make things work the way I expected to by storing the environment table for an object instance in the global registry (I set it in set_instance_value).  This prevents the table from being garbage collected. I remove it from the global registry after the __finalize method has been called on the object in destroy_instance.

I'd be interested to hear what the developers have to say about this "issue" and fix.

Max

--
Technical Director
Unknown Worlds Entertainment
http://www.unknownworlds.com


On Tue, Aug 31, 2010 at 6:00 PM, Max McGuire <[hidden email]> wrote:
I've run into some unexpected behavior with the __finalize method. Specifically if my class has members that are also classes, the __finalize methods for the members are getting called before the __finalize method for the owner.

Here's a simple example:

class 'B'

function B:__finalize()
    print("B:__finalize\n")
end

class 'A'

function A:__init()
    self.b = B()
end

function A:__finalize()
    print("A:__finalize\n")
end

local a = A()
a = nil

collectgarbage("collect")

The output from this program is:

B:__finalize
A:__finalize

This is the opposite behavior that you would get from a C++ program and is problematic, especially if B is actually a class implemented in C++ and you tried to access b during the __finalize method for A.

Is this by design or am I missing something?

Thanks,

Max

--
Technical Director
Unknown Worlds Entertainment
http://www.unknownworlds.com


------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Unexpected order of __finalize

Nigel Atkinson-2
Well that's strange!  Oh wait.. ah ha! I tried your program in an
interactive Lua console, with luabind and found something not very
obvious if you were running this as a complete chunk.

The program is actually failing to completely create a 'B', as there is
no __init() function for it.  So the 'B' finalise gets called, and
because there was an error in the A init, A gets zapped and finalised as
well.  In that order.  The program only makes it to "local a = A()"

It seems to work as expected if you add an init function for B.

Nigel

On Tue, 2010-08-31 at 18:54 -0700, Max McGuire wrote:

> For what it's worth, I was able to make things work the way I expected
> to by storing the environment table for an object instance in the
> global registry (I set it in set_instance_value).  This prevents the
> table from being garbage collected. I remove it from the global
> registry after the __finalize method has been called on the object in
> destroy_instance.
>
> I'd be interested to hear what the developers have to say about this
> "issue" and fix.
>
> Max
>
> --
> Technical Director
> Unknown Worlds Entertainment
> http://www.unknownworlds.com
>
>
> On Tue, Aug 31, 2010 at 6:00 PM, Max McGuire <[hidden email]>
> wrote:
>         I've run into some unexpected behavior with the __finalize
>         method. Specifically if my class has members that are also
>         classes, the __finalize methods for the members are getting
>         called before the __finalize method for the owner.
>        
>         Here's a simple example:
>        
>         class 'B'
>        
>         function B:__finalize()
>             print("B:__finalize\n")
>         end
>        
>         class 'A'
>        
>         function A:__init()
>             self.b = B()
>         end
>        
>         function A:__finalize()
>             print("A:__finalize\n")
>         end
>        
>         local a = A()
>         a = nil
>        
>         collectgarbage("collect")
>        
>        
>         The output from this program is:
>        
>         B:__finalize
>         A:__finalize
>        
>        
>         This is the opposite behavior that you would get from a C++
>         program and is problematic, especially if B is actually a
>         class implemented in C++ and you tried to access b during the
>         __finalize method for A.
>        
>         Is this by design or am I missing something?
>        
>         Thanks,
>        
>         Max
>        
>         --
>         Technical Director
>         Unknown Worlds Entertainment
>         http://www.unknownworlds.com
>
> ------------------------------------------------------------------------------
> This SF.net Dev2Dev email is sponsored by:
>
> Show off your parallel programming skills.
> Enter the Intel(R) Threading Challenge 2010.
> http://p.sf.net/sfu/intel-thread-sfd
> _______________________________________________ luabind-user mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/luabind-user



------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Unexpected order of __finalize

Max McGuire
I forgot that I modified luabind to not require an __init method. I'm not sure why you are getting different results with the __init added though, I'll have to try with an unmodified version of luabind.

Max

--
Technical Director
Unknown Worlds Entertainment
http://www.unknownworlds.com


On Tue, Aug 31, 2010 at 8:58 PM, Nigel Atkinson <[hidden email]> wrote:
Well that's strange!  Oh wait.. ah ha! I tried your program in an
interactive Lua console, with luabind and found something not very
obvious if you were running this as a complete chunk.

The program is actually failing to completely create a 'B', as there is
no __init() function for it.  So the 'B' finalise gets called, and
because there was an error in the A init, A gets zapped and finalised as
well.  In that order.  The program only makes it to "local a = A()"

It seems to work as expected if you add an init function for B.

Nigel

On Tue, 2010-08-31 at 18:54 -0700, Max McGuire wrote:
> For what it's worth, I was able to make things work the way I expected
> to by storing the environment table for an object instance in the
> global registry (I set it in set_instance_value).  This prevents the
> table from being garbage collected. I remove it from the global
> registry after the __finalize method has been called on the object in
> destroy_instance.
>
> I'd be interested to hear what the developers have to say about this
> "issue" and fix.
>
> Max
>
> --
> Technical Director
> Unknown Worlds Entertainment
> http://www.unknownworlds.com
>
>
> On Tue, Aug 31, 2010 at 6:00 PM, Max McGuire <[hidden email]>
> wrote:
>         I've run into some unexpected behavior with the __finalize
>         method. Specifically if my class has members that are also
>         classes, the __finalize methods for the members are getting
>         called before the __finalize method for the owner.
>
>         Here's a simple example:
>
>         class 'B'
>
>         function B:__finalize()
>             print("B:__finalize\n")
>         end
>
>         class 'A'
>
>         function A:__init()
>             self.b = B()
>         end
>
>         function A:__finalize()
>             print("A:__finalize\n")
>         end
>
>         local a = A()
>         a = nil
>
>         collectgarbage("collect")
>
>
>         The output from this program is:
>
>         B:__finalize
>         A:__finalize
>
>
>         This is the opposite behavior that you would get from a C++
>         program and is problematic, especially if B is actually a
>         class implemented in C++ and you tried to access b during the
>         __finalize method for A.
>
>         Is this by design or am I missing something?
>
>         Thanks,
>
>         Max
>
>         --
>         Technical Director
>         Unknown Worlds Entertainment
>         http://www.unknownworlds.com
>
> ------------------------------------------------------------------------------
> This SF.net Dev2Dev email is sponsored by:
>
> Show off your parallel programming skills.
> Enter the Intel(R) Threading Challenge 2010.
> http://p.sf.net/sfu/intel-thread-sfd
> _______________________________________________ luabind-user mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/luabind-user



------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user


------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Unexpected order of __finalize

Max McGuire
I tested with an unmodified version of luabind (0.9) and Lua 5.1.4 and I get the same result (B:__finalize followed by A:__finalize).

Unfortunatly the fix I proposed doesn't work in the case when the Lua state is being destroyed. In this case the __gc metamethod is called on all remaining user data in an arbitrary order.

I've attached a simple program which crashes (pure virtual function call with MSVC 2005) due to this issue.

Max

--
Technical Director
Unknown Worlds Entertainment
http://www.unknownworlds.com


On Wed, Sep 1, 2010 at 8:09 AM, Max McGuire <[hidden email]> wrote:
I forgot that I modified luabind to not require an __init method. I'm not sure why you are getting different results with the __init added though, I'll have to try with an unmodified version of luabind.

Max

--
Technical Director
Unknown Worlds Entertainment
http://www.unknownworlds.com


On Tue, Aug 31, 2010 at 8:58 PM, Nigel Atkinson <[hidden email]> wrote:
Well that's strange!  Oh wait.. ah ha! I tried your program in an
interactive Lua console, with luabind and found something not very
obvious if you were running this as a complete chunk.

The program is actually failing to completely create a 'B', as there is
no __init() function for it.  So the 'B' finalise gets called, and
because there was an error in the A init, A gets zapped and finalised as
well.  In that order.  The program only makes it to "local a = A()"

It seems to work as expected if you add an init function for B.

Nigel

On Tue, 2010-08-31 at 18:54 -0700, Max McGuire wrote:
> For what it's worth, I was able to make things work the way I expected
> to by storing the environment table for an object instance in the
> global registry (I set it in set_instance_value).  This prevents the
> table from being garbage collected. I remove it from the global
> registry after the __finalize method has been called on the object in
> destroy_instance.
>
> I'd be interested to hear what the developers have to say about this
> "issue" and fix.
>
> Max
>
> --
> Technical Director
> Unknown Worlds Entertainment
> http://www.unknownworlds.com
>
>
> On Tue, Aug 31, 2010 at 6:00 PM, Max McGuire <[hidden email]>
> wrote:
>         I've run into some unexpected behavior with the __finalize
>         method. Specifically if my class has members that are also
>         classes, the __finalize methods for the members are getting
>         called before the __finalize method for the owner.
>
>         Here's a simple example:
>
>         class 'B'
>
>         function B:__finalize()
>             print("B:__finalize\n")
>         end
>
>         class 'A'
>
>         function A:__init()
>             self.b = B()
>         end
>
>         function A:__finalize()
>             print("A:__finalize\n")
>         end
>
>         local a = A()
>         a = nil
>
>         collectgarbage("collect")
>
>
>         The output from this program is:
>
>         B:__finalize
>         A:__finalize
>
>
>         This is the opposite behavior that you would get from a C++
>         program and is problematic, especially if B is actually a
>         class implemented in C++ and you tried to access b during the
>         __finalize method for A.
>
>         Is this by design or am I missing something?
>
>         Thanks,
>
>         Max
>
>         --
>         Technical Director
>         Unknown Worlds Entertainment
>         http://www.unknownworlds.com
>
> ------------------------------------------------------------------------------
> This SF.net Dev2Dev email is sponsored by:
>
> Show off your parallel programming skills.
> Enter the Intel(R) Threading Challenge 2010.
> http://p.sf.net/sfu/intel-thread-sfd
> _______________________________________________ luabind-user mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/luabind-user



------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user



------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user

Main.cpp (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Unexpected order of __finalize

Nigel Atkinson-2
Hmm, I tried it again and now get the same results as you do.  I must
have accidentally done something different last time.

I have encountered the different order of gc with lua_close myself.  In
the end I re-arranged my code to not have parent objects destroy child
objects on finalise.

Nigel

On Wed, 2010-09-01 at 09:48 -0700, Max McGuire wrote:

> I tested with an unmodified version of luabind (0.9) and Lua 5.1.4 and
> I get the same result (B:__finalize followed by A:__finalize).
>
> Unfortunatly the fix I proposed doesn't work in the case when the Lua
> state is being destroyed. In this case the __gc metamethod is called
> on all remaining user data in an arbitrary order.
>
> I've attached a simple program which crashes (pure virtual function
> call with MSVC 2005) due to this issue.
>
> Max
>
> --
> Technical Director
> Unknown Worlds Entertainment
> http://www.unknownworlds.com
>
>
> On Wed, Sep 1, 2010 at 8:09 AM, Max McGuire <[hidden email]>
> wrote:
>         I forgot that I modified luabind to not require an __init
>         method. I'm not sure why you are getting different results
>         with the __init added though, I'll have to try with an
>         unmodified version of luabind.
>        
>         Max
>        
>         --
>         Technical Director
>         Unknown Worlds Entertainment
>         http://www.unknownworlds.com
>        
>        
>        
>        
>         On Tue, Aug 31, 2010 at 8:58 PM, Nigel Atkinson
>         <[hidden email]> wrote:
>                 Well that's strange!  Oh wait.. ah ha! I tried your
>                 program in an
>                 interactive Lua console, with luabind and found
>                 something not very
>                 obvious if you were running this as a complete chunk.
>                
>                 The program is actually failing to completely create a
>                 'B', as there is
>                 no __init() function for it.  So the 'B' finalise gets
>                 called, and
>                 because there was an error in the A init, A gets
>                 zapped and finalised as
>                 well.  In that order.  The program only makes it to
>                 "local a = A()"
>                
>                 It seems to work as expected if you add an init
>                 function for B.
>                
>                 Nigel
>                
>                
>                 On Tue, 2010-08-31 at 18:54 -0700, Max McGuire wrote:
>                 > For what it's worth, I was able to make things work
>                 the way I expected
>                 > to by storing the environment table for an object
>                 instance in the
>                 > global registry (I set it in set_instance_value).
>                  This prevents the
>                 > table from being garbage collected. I remove it from
>                 the global
>                 > registry after the __finalize method has been called
>                 on the object in
>                 > destroy_instance.
>                 >
>                 > I'd be interested to hear what the developers have
>                 to say about this
>                 > "issue" and fix.
>                 >
>                 > Max
>                 >
>                 > --
>                 > Technical Director
>                 > Unknown Worlds Entertainment
>                 > http://www.unknownworlds.com
>                 >
>                 >
>                 > On Tue, Aug 31, 2010 at 6:00 PM, Max McGuire
>                 <[hidden email]>
>                 > wrote:
>                 >         I've run into some unexpected behavior with
>                 the __finalize
>                 >         method. Specifically if my class has members
>                 that are also
>                 >         classes, the __finalize methods for the
>                 members are getting
>                 >         called before the __finalize method for the
>                 owner.
>                 >
>                 >         Here's a simple example:
>                 >
>                 >         class 'B'
>                 >
>                 >         function B:__finalize()
>                 >             print("B:__finalize\n")
>                 >         end
>                 >
>                 >         class 'A'
>                 >
>                 >         function A:__init()
>                 >             self.b = B()
>                 >         end
>                 >
>                 >         function A:__finalize()
>                 >             print("A:__finalize\n")
>                 >         end
>                 >
>                 >         local a = A()
>                 >         a = nil
>                 >
>                 >         collectgarbage("collect")
>                 >
>                 >
>                 >         The output from this program is:
>                 >
>                 >         B:__finalize
>                 >         A:__finalize
>                 >
>                 >
>                 >         This is the opposite behavior that you would
>                 get from a C++
>                 >         program and is problematic, especially if B
>                 is actually a
>                 >         class implemented in C++ and you tried to
>                 access b during the
>                 >         __finalize method for A.
>                 >
>                 >         Is this by design or am I missing something?
>                 >
>                 >         Thanks,
>                 >
>                 >         Max
>                 >
>                 >         --
>                 >         Technical Director
>                 >         Unknown Worlds Entertainment
>                 >         http://www.unknownworlds.com
>                 >
>                
>                 >
>                 ------------------------------------------------------------------------------
>                 > This SF.net Dev2Dev email is sponsored by:
>                 >
>                 > Show off your parallel programming skills.
>                 > Enter the Intel(R) Threading Challenge 2010.
>                 > http://p.sf.net/sfu/intel-thread-sfd
>                 > _______________________________________________
>                 luabind-user mailing list
>                 [hidden email]
>                 https://lists.sourceforge.net/lists/listinfo/luabind-user
>                
>                
>                
>                 ------------------------------------------------------------------------------
>                 This SF.net Dev2Dev email is sponsored by:
>                
>                 Show off your parallel programming skills.
>                 Enter the Intel(R) Threading Challenge 2010.
>                 http://p.sf.net/sfu/intel-thread-sfd
>                 _______________________________________________
>                 luabind-user mailing list
>                 [hidden email]
>                 https://lists.sourceforge.net/lists/listinfo/luabind-user
>        
>        
>
> ------------------------------------------------------------------------------
> This SF.net Dev2Dev email is sponsored by:
>
> Show off your parallel programming skills.
> Enter the Intel(R) Threading Challenge 2010.
> http://p.sf.net/sfu/intel-thread-sfd
> _______________________________________________ luabind-user mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/luabind-user



------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user