librelist archives

« back to archive

Constructor overload

Constructor overload

From:
Noel Warren
Date:
2012-05-31 @ 23:16
So the library I'm trying to wrap has a few classes that fave overloaded
constructors.  How would I go about this little problem?  Perhaps a cover
method that takes one Object from ruby and then inspects it (If it is an
array they could be various arguments)?  Thanks

Re: [rice] Constructor overload

From:
Paul Brannan
Date:
2012-06-01 @ 02:20
Short answer: define a class method which wraps a new instance of the
class, like this:

    Data_Object<MyClass> obj(
            new MyClass(arg1, arg2, ...), // create new c++ instance
            rb_cMyClass); // ruby class to wrap instance in
    return obj;

There is no builtin shortcut for having an alternative constructor, but
there could/should be.

Ruby allows multiple constructors per class, but they must have different
(hopefully descriptive) names.  In C++, constructors do not have names at
all.  The name of the usual constructor in Ruby is called 'new', as in
Object.new.  The .new method conceptually does something like this:

    def new(*args)
        object = allocate()
        object.initialize(*args)
        return object
    end

An example of a good descriptive name for an alternative constructor would
be File.for_fd or URI.parse, e.g.:

    file = File.for_fd(2); file.puts("hello")
    uri = URI.parse("http://ruby-lang.org")

An example of a poor descriptive name would be XMLRPC::Client.new2 (this
doesn't tell me anything about the constructor).

Now how do you write a constructor using Rice?  The usual
define_constructor() function does two things:

   1. It defines a class method .allocate which allocates the object and
   sets its data pointer to 0 (this ensures that if GC kicks in before the
   object is fully constructed, it will be properly destructed).
   2. It defines an instance method #initialize which does the actual work
   of construction via something like: DATA_PTR(self) = new MyClass(arg1,
   arg2, ...)

Since Object.new is builtin to Ruby, derived classes do not redefine it.
 For an alternative constructor method, you need something which does the
same thing as Object.new.  However, it need not necessarily separate
allocation and initialization; it can do it all in one function (as per the
example up top).

It is possible to write the .new method so that it is variadic (that is,
one function which accepts varying number/types of arguments; I think this
is what you were originally asking).  This is not, however, good idiomatic
Ruby.

Jason, I think this is an FAQ and we should add something about it to the
docs.

Paul

On Thu, May 31, 2012 at 7:16 PM, Noel Warren <noelwarr@gmail.com> wrote:

> So the library I'm trying to wrap has a few classes that fave overloaded
> constructors.  How would I go about this little problem?  Perhaps a cover
> method that takes one Object from ruby and then inspects it (If it is an
> array they could be various arguments)?  Thanks

Re: [rice] Constructor overload

From:
Jason Roelofs
Date:
2012-06-07 @ 01:32
Paul,

Awesome explanation, I'll make a note to add this to the documentation. Thanks!

Jason

On May 31, 2012, at 10:20 PM, Paul Brannan wrote:

> Short answer: define a class method which wraps a new instance of the 
class, like this:
> 
>     Data_Object<MyClass> obj(
>             new MyClass(arg1, arg2, ...), // create new c++ instance
>             rb_cMyClass); // ruby class to wrap instance in
>     return obj;
> 
> There is no builtin shortcut for having an alternative constructor, but 
there could/should be.
> 
> Ruby allows multiple constructors per class, but they must have 
different (hopefully descriptive) names.  In C++, constructors do not have
names at all.  The name of the usual constructor in Ruby is called 'new', 
as in Object.new.  The .new method conceptually does something like this:
> 
>     def new(*args)
>         object = allocate()
>         object.initialize(*args)
>         return object
>     end
> 
> An example of a good descriptive name for an alternative constructor 
would be File.for_fd or URI.parse, e.g.:
> 
>     file = File.for_fd(2); file.puts("hello")
>     uri = URI.parse("http://ruby-lang.org")
> 
> An example of a poor descriptive name would be XMLRPC::Client.new2 (this
doesn't tell me anything about the constructor).
> 
> Now how do you write a constructor using Rice?  The usual 
define_constructor() function does two things:
> It defines a class method .allocate which allocates the object and sets 
its data pointer to 0 (this ensures that if GC kicks in before the object 
is fully constructed, it will be properly destructed).
> It defines an instance method #initialize which does the actual work of 
construction via something like: DATA_PTR(self) = new MyClass(arg1, arg2, 
...)
> Since Object.new is builtin to Ruby, derived classes do not redefine it.
For an alternative constructor method, you need something which does the 
same thing as Object.new.  However, it need not necessarily separate 
allocation and initialization; it can do it all in one function (as per 
the example up top).
> 
> It is possible to write the .new method so that it is variadic (that is,
one function which accepts varying number/types of arguments; I think this
is what you were originally asking).  This is not, however, good idiomatic
Ruby.
> 
> Jason, I think this is an FAQ and we should add something about it to the docs.
> 
> Paul
> 
> On Thu, May 31, 2012 at 7:16 PM, Noel Warren <noelwarr@gmail.com> wrote:
> So the library I'm trying to wrap has a few classes that fave overloaded
constructors.  How would I go about this little problem?  Perhaps a cover 
method that takes one Object from ruby and then inspects it (If it is an 
array they could be various arguments)?  Thanks
>