Member variables dependency policy

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

Member variables dependency policy

Max McGuire
I'm running into a problem with luabind automatically creating a dependency between a member variable and the parent object. This functionality is described in the documentation:

struct A { int m; };
struct B { A a; };

When binding B to lua, the following expression code should work:

b = B()
b.a.m = 1
assert(b.a.m == 1)

This requires the first lookup (on a) to return a reference to A, and not a copy. In that case, luabind will automatically use the dependency policy to make the return value dependent on the object in which it is stored. So, if the returned reference lives longer than all references to the object (b in this case) it will keep the object alive, to avoid being a dangling pointer.

In my case, B actually contains a pointer to A, and B does not own this pointer. The object being pointed to is expected to outlive the instance B, which causes a problem.  When I access "a" from Lua, luabind creates a dependency between a and b so that b won't be collected until a is collected. Since a outlives b, this creates a condition where I accumulate dependencies and Lua is never able to garbage collect them.

I was able to work around this by creating getter/setter methods for the "a" member variable (without the dependency policy), but I'm wondering what the correct way to solve this problem is.

Max

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

------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Member variables dependency policy

Daniel Wallin
On Tue, Mar 23, 2010 at 01:42:15PM -0700, Max McGuire wrote:

> I'm running into a problem with luabind automatically creating a dependency
> between a member variable and the parent object. This functionality is
> described in the documentation:
>
> struct A { int m; };
> struct B { A a; };
>
> When binding B to lua, the following expression code should work:
>
> b = B()
> b.a.m = 1
> assert(b.a.m == 1)
>
> This requires the first lookup (on a) to return a reference to A, and not a
> copy. In that case, luabind will automatically use the dependency policy to
> make the return value dependent on the object in which it is stored. So, if
> the returned reference lives longer than all references to the object (b in
> this case) it will keep the object alive, to avoid being a dangling pointer.
>
> In my case, B actually contains a pointer to A, and B does not own this
> pointer. The object being pointed to is expected to outlive the instance B,
> which causes a problem.  When I access "a" from Lua, luabind creates a
> dependency between a and b so that b won't be collected until a is
> collected. Since a outlives b, this creates a condition where I accumulate
> dependencies and Lua is never able to garbage collect them.
>
> I was able to work around this by creating getter/setter methods for the "a"
> member variable (without the dependency policy), but I'm wondering what the
> correct way to solve this problem is.

Interesting. I can see two solutions:

1. Change the default behaviour so that pointer members doesn't
   imply a dependency.

2. Add a dummy policy, similar to "yield", that can be used to suppress
   the dependency:

     def_readwrite(&B::a, no_dependency)

I'm leaning toward (2) because it's generally more safe to assume
ownership. Doing (1) might mean we end up with a lot of code that SHOULD
use dependency() but doesn't because the user overlooked the detail.
Also, (1) breaks backward compatibility, but I'm willing to do that if
it's a better design.

What do you think?

--
Daniel Wallin
BoostPro Computing
http://www.boostpro.com

------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Member variables dependency policy

Max McGuire
I think either of those would be good solutions.

I know for my style of programming, it's unlikely I'd have a member variable of a C++ class be public if it was owned by the containing class, which makes me personally prefer not to have default dependencies for pointers.  However, there's enough subtlety involved with interfacing C++ objects with Lua, especially concerning garbage collection, that a little extra work specifying no dependency isn't a big deal.

One thing I would suggest adding is a check in add_dependency to make sure you aren't "overflowing" the maximum number of dependencies:

void object_rep::add_dependency(lua_State* L, int index)
{

    // Trigger an error when we exceed the maximum number of dependencies
    // we can support. The max number of dependencies if based off the size
    // of the object because it allows us to give them unique IDs without
    // having to do any additional book keeping.
    if (m_dependency_cnt >= sizeof(object_rep))
    {
        luaL_error(L, "maximum number of dependencies (%d) for an object reached", sizeof(object_rep));
    }

    ....

Max

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


On Wed, Mar 24, 2010 at 6:09 AM, Daniel Wallin <[hidden email]> wrote:
On Tue, Mar 23, 2010 at 01:42:15PM -0700, Max McGuire wrote:
> I'm running into a problem with luabind automatically creating a dependency
> between a member variable and the parent object. This functionality is
> described in the documentation:
>
> struct A { int m; };
> struct B { A a; };
>
> When binding B to lua, the following expression code should work:
>
> b = B()
> b.a.m = 1
> assert(b.a.m == 1)
>
> This requires the first lookup (on a) to return a reference to A, and not a
> copy. In that case, luabind will automatically use the dependency policy to
> make the return value dependent on the object in which it is stored. So, if
> the returned reference lives longer than all references to the object (b in
> this case) it will keep the object alive, to avoid being a dangling pointer.
>
> In my case, B actually contains a pointer to A, and B does not own this
> pointer. The object being pointed to is expected to outlive the instance B,
> which causes a problem.  When I access "a" from Lua, luabind creates a
> dependency between a and b so that b won't be collected until a is
> collected. Since a outlives b, this creates a condition where I accumulate
> dependencies and Lua is never able to garbage collect them.
>
> I was able to work around this by creating getter/setter methods for the "a"
> member variable (without the dependency policy), but I'm wondering what the
> correct way to solve this problem is.

Interesting. I can see two solutions:

1. Change the default behaviour so that pointer members doesn't
  imply a dependency.

2. Add a dummy policy, similar to "yield", that can be used to suppress
  the dependency:

    def_readwrite(&B::a, no_dependency)

I'm leaning toward (2) because it's generally more safe to assume
ownership. Doing (1) might mean we end up with a lot of code that SHOULD
use dependency() but doesn't because the user overlooked the detail.
Also, (1) breaks backward compatibility, but I'm willing to do that if
it's a better design.

What do you think?

--
Daniel Wallin
BoostPro Computing
http://www.boostpro.com

------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user


------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Member variables dependency policy

Nigel Atkinson-2
In reply to this post by Daniel Wallin
For my 2 cents, I prefer the second option, as it helps document the
intent of who ever wrote the code - in other words it's self
documenting.  Also bugs arising from option 1 and a user overlooking the
detail would quite hard to track down.  Especially if you are the one
that did the overlooking! ;-)

Nigel

On Wed, 2010-03-24 at 14:09 +0100, Daniel Wallin wrote:

> 1. Change the default behaviour so that pointer members doesn't
>    imply a dependency.
>
> 2. Add a dummy policy, similar to "yield", that can be used to suppress
>    the dependency:
>
>      def_readwrite(&B::a, no_dependency)
>
> I'm leaning toward (2) because it's generally more safe to assume
> ownership. Doing (1) might mean we end up with a lot of code that SHOULD
> use dependency() but doesn't because the user overlooked the detail.
> Also, (1) breaks backward compatibility, but I'm willing to do that if
> it's a better design.
>
> What do you think?
>



------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user