inheritance from C object with different parameter count

G

Geert Fannes

------_=_NextPart_001_01C6257C.D03CA54C
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

Hello,

I'm trying to create a derived class (ruby class) from a C-implemented
class. Everything works fine, until I tried to add a parameter to the
derived class. When I derive from a pure ruby base class, everything
works as should be, extra parameter or not. Does someone know what is
going on or what I am doing wrong?

=20

I am getting the following output:

=20

gfannes@lt-gfannes help $ ruby test.rb

test.rb:21:in `new': wrong number of arguments (1 for 0) (ArgumentError)

from test.rb:21

=20

=20

This is the ruby file containing the derivation from the base class. If
bCLib is set to false, things work as should be.

##############test.rb######################

bCLib=3Dtrue

=20

if bCLib

require('base.so')

else

class Base

def initialize()

puts("base")

end

end

end

=20

class Derived < Base

def initialize(parameter)

puts("init derived")

super()

puts("finished super")

end

end

=20

Derived.new('parameter')

##########################################

=20

This is the C-file that implements the base class in C
######################base.c#####################

#include "ruby.h"

#include <stdio.h>

#include <malloc.h>

=20

typedef struct{

double dValue;

} baseStruct;

=20

=20

VALUE f_new0(VALUE klass)

{

printf("f_new0.\n");

VALUE rBase;

baseStruct *pBase=3Dmalloc(sizeof(baseStruct));

rBase =3D Data_Wrap_Struct(klass, 0, free, pBase);

printf("before rb_obj_call_init.\n");

rb_obj_call_init(rBase, 0, 0);

printf("f_new0 finished.\n");

return rBase;

}

=20

VALUE f_initialize0(VALUE self)

{

printf("f_initialize0.\n");

return self;

}

=20

VALUE cBase;

=20

void Init_base()

{

cBase=3Drb_define_class("Base",rb_cObject);

rb_define_singleton_method(cBase, "new", f_new0, 0);

rb_define_method (cBase, "initialize", f_initialize0, 0); }
#################################################

=20

Everything is compiled using extconf.rb

#############extconf.rb##########################

require 'mkmf'

create_makefile('base')

#################################################

=20


------_=_NextPart_001_01C6257C.D03CA54C--
 
E

Esteban Manchado Velázquez

--3siQDZowHQqNOShm
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hello,
=20
I'm trying to create a derived class (ruby class) from a C-implemented
class. Everything works fine, until I tried to add a parameter to the
derived class. When I derive from a pure ruby base class, everything
works as should be, extra parameter or not. Does someone know what is
going on or what I am doing wrong?

Hmmm... weird. If you comment the "super()" call in Derived#initialize,=
it
dies with the exact same error. In fact, you don't even get the "init deriv=
ed"
message.

After investigating a little, I found out that changing the definition =
of
new to:

rb_define_singleton_method(cBase, "new", f_new0, -1);

makes it work. I don't know if that's entirely correct (I'm not very famili=
ar
with C extensions), but it works :) I guess the problem is that, as you do=
n't
redefine the "new" method in the class Derived, you get the Base one, so it
chokes. I don't know if the usual thing here is always defining "new" metho=
ds
with any parameter count...

HTH,

--=20
Esteban Manchado Vel=E1zquez <[email protected]> - http://www.foton.es
EuropeSwPatentFree - http://EuropeSwPatentFree.hispalinux.es

--3siQDZowHQqNOShm
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFD3gMkhYgK5b1UDsERAvC0AJ9V/NvJSedzTHYPpN2/1NLzJl0IMQCeIcBZ
0C3ygKmGThVW5qCaHqOqgDc=
=4+ug
-----END PGP SIGNATURE-----

--3siQDZowHQqNOShm--
 
G

George Ogata

Geert Fannes said:
I'm trying to create a derived class (ruby class) from a C-implemented
class. Everything works fine, until I tried to add a parameter to the
derived class. When I derive from a pure ruby base class, everything
works as should be, extra parameter or not. Does someone know what is
going on or what I am doing wrong?

Your C code does not do:

class Base
def initialize()
puts("base")
end
end

It's more like:

class Base
def self.new
...
end
def self.initialize
...
end
end

Thus, Derived.new(arg) is an error, since it calls Base.new, which
you've defined to take no args.

Note that Blah.new is a completely different method to
Blah#initialize. Blah.new would be a singleton method of the Class
instance Blah, but you usually don't want that, as the standard
Class#new is sufficiently magical to do everything you need. In
pseudoruby, it looks like:

class Class
def new(*args)
object = self.alloc_func
object.initialize(*args)
return object
end
end

Object#dup and Object#clone are similar:

class Object
def dup(other)
object = self.alloc_func
object.initialize_copy(other)
return object
end
def clone(other)
object = self.alloc_func
object.singleton_class = other.singleton_class.copy
# ... some other diddly bits ...
object.initialize_copy(other)
return object
end
end

So what you normally do is:

-- define the alloc func to alloc a ruby object from heap memory:
VALUE Thingy_allocate(VALUE klass) {
struct Thingy *thingy;
return Data_Make_Struct(klass, struct Thingy,
Thingy_mark, Thingy_free, thingy);
}

-- define an #initialize method:
VALUE Thingy_initialize(VALUE self, ...args...) {
...
}

-- define an #initialize_copy method:
VALUE Thingy_initialize_copy(VALUE self, VALUE other) {
...
}

-- bind 'em:
void Init_libthingies {
VALUE cThingy;
cThingy = rb_define_class("Thingy", rb_cObject);
rb_define_alloc_func(cThingy, Thingy_allocate);
rb_define_method(cThingy, "initialize", Thingy_initialize, num_args);
rb_define_method(cThingy, "initialize", Thingy_initialize_copy, 1);
...
}

Of course, #initialize_copy is optional (in fact, so is #initialize),
but the point is that doing things this way means you only have to do
the malloc-ing once (in the alloc func), and everywhere else you're
dealing with a perfectly valid ruby object. No need to call
#initialize or obj_call_init() or worry about your object not being
allocated if #initialize is overriden or gets interrupted by an
exception... just let the standard methods call your hooks and lie
back. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top