Forums | Admin

Discussion Forums: help

Start New Thread Start New Thread

 

By: Mikkel Garcia
RE: Proper way to return an object to wrap? [ reply ]  
2008-05-03 22:51
I finally found out how to do this :)

In your example:

Object ClassOne::getOtherObject()
{
return Data_Object<ClassTwo>(myPointerToAClassTwo);
}

can be written as:

Object ClassOne::getOtherObject()
{
Rice::Data_Object<ClassTwo>(myPointerToAClassTwo, Rice::Data_Type<ClassTwo>::klass(), 0, 0);
}

The third argument points to a mark function, called by ruby when marking your object (so you can mark dependants), and the fourth argument specifies a delete function. For this case, since we don't want the GC to do anything, we specify a null value.

Hope it helps,
-Mikkel

By: Peter Jaros
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-18 18:31
All right, so to make sure I understand (Address_Registration_Guard aside):

* Any object I return into Ruby will be GC'd.
* The only ways around this are to copy the object (and let the copy be destroyed as Ruby sees fit) or to create a proxy object duplicating its interface (which can be destroyed without affecting the original object)

Is that right?

By: Paul Brannan
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-18 17:09
Well-written, Mikkel. You *can* temporarily prevent Ruby from GC'ing an object with an Address_Registration_Guard (which calls rb_gc_register_address). For it to work, you must keep a copy of the wrapped Object around and pass the constructor of the Address_Registration_Guard a pointer to the Object. However, the object will still be destroyed when Ruby exits, and there's no way around this.

The delegate solution is interesting (and is essentially what I do when I wrap smart pointers), but I haven't given any thought to simplifying it. I can imagine lots of uses for a generalized idiom for doing this.


By: Mikkel Garcia
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-18 16:54
Hi Peter

Paul, correct me if I'm wrong, but from what I understand, Ruby will try to clean up any object that it gets ahold of.

That means if you have a:
class World {
private:
Scene * m_scene;
public:
World() { m_scene = new Scene(); }
Scene *getScene() { return m_scene; }
};

Then, your options to get the scene object are:

1. Copy the Scene object instance and return it.
Note: This is not appropriate in many situations. Any changes you make to the copied scene won't be made to the World's scene.

2. Create a class that delegates to Scene.
Note 1: When the GC attempts to clean up the SceneDelegate class, the Scene class will not be deleted.
Note 2: Redoing the interface for Scene in this delegate class sucks.
Note 3: This is not very detailed, let me know if you would like an example.

3. There seems like there should be an option for telling Ruby to not GC an object, ever. Any ideas?
Note 1: gc_mark doesn't seem to do it.
Note 2: gc_register_address doesn't seem to either.

By: Paul Brannan
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-18 16:54
Right, I forgot about that. You can make a copy with:

return Data_Object<ClassTwo>(new ClassTwo(*c2));

By: Peter Jaros
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-18 16:24
Ok. But that's still bad code, right? Ruby's GC is going to try to clean up my ClassTwo, which my ClassOne object owns and still needs.

By: Paul Brannan
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-18 14:54
Since your function returns non-const, I think your to_ruby specialization should take a pointer to non-const as a parameter.

By: Peter Jaros
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-18 14:50
Ok. How would I implement a to_ruby() in this case? All I can think of is

template<>
Object to_ruby<ClassTwo *>(ClassTwo const * c2)
{
return Data_Object<ClassTwo>(c2);
}

Which obviously is the same problem over again. Is there some way to wrap an object without giving the wrapper ownership of the object?

By: Paul Brannan
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-17 14:03
Actually the conversions are generated when Data_Type<T>::bind() is called (which should happen when define_class<> is called).

The latest release of Rice does not automatically generate conversions for pointers. There is support for this in in svn, but it will have the wrong behavior with your example, as it will assume ownership of the object.

Rice cannot know what the intended semantics are for the return value of a given function without help from the user. The new method attributes framework should allow the user to specify the semantics of the return value, but for the moment, this only exists in my (and Jason's) head.

Until the next version of Rice is available, if you want this conversion to work, you will need to define a to_ruby() function that takes a ClassTwo* parameter and returns an Object.

By: Peter Jaros
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-17 02:28
Actually, I get the exact same errors. Here's my new code:

http://pastie.textmate.org/182129

By: Jason Roelofs
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-17 00:16
Ah yes, the to_ from_ruby conversions are built after you wrap the constructor. Add:

define_constructor(Constructor<ClassTwo>())
define_constructor(Constructor<ClassOne>())

to the appropriate places, that should fix it.

By: Peter Jaros
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-16 22:53
Thanks for replying so fast!

I have, and that doesn't seem to fix it. Here's a reduced test case:

http://pastie.textmate.org/182023

This code fails to compile with these messages:

http://pastie.textmate.org/182031

Commenting out the first define_method lets the code compile.

By: Jason Roelofs
RE: Proper way to return an object to wrap? [ reply ]  
2008-04-16 22:12
Have you tried moving the define_class of ClassTwo to be before ClassOne? Other than that, could you post more code to help us debug this problem?

By: Peter Jaros
Proper way to return an object to wrap? [ reply ]  
2008-04-16 21:58
I have two classes which are wrapped with Rice using define_class<T>. One of them holds a pointer to an instance of the other. I want to make an accessor to the expose that relationship. If I do:

ClassTwo *ClassOne::getOtherObject()
{
return myPointerToAClassTwo;
}

Rice complains on compile that there's no to_ruby defined for ClassTwo*. I've successfully used:

Object ClassOne::getOtherObject()
{
return Data_Object<ClassTwo>(myPointerToAClassTwo);
}

But that'll reintroduce the ClassTwo object to the GC system every time it's called, right? What's the correct way to do this?