From: Lyle Johnson Date: 2002-02-12T23:31:50+09:00 Subject: Proposed Modification for SWIG/Ruby This note describes a perceived problem with SWIG's Ruby module and the proposed solution. Before I proceed with implementing the solution in the development version of SWIG I wanted to run it by the SWIG developers' list and the Ruby community at large. Any comments and suggestions are appreciated. The Problem ============ The SWIG/Ruby module's current treatment for C++ class constructors is to generate a "new" singleton method only. For example, consider the following SWIG interface file: class Base { public: Base(); }; which results in the following wrapper function: static VALUE _wrap_new_Base(int argc, VALUE *argv, VALUE self) { Base *result; VALUE vresult = Qnil; if ((argc < 0) || (argc > 0)) rb_raise(rb_eArgError, "wrong # of arguments(%d for 0)",argc); result = (Base *) new Base(); vresult = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_Base, 1); return vresult; } which is correctly registered as a singleton method for the Base class. On its own this works properly; when the resulting extension module is imported by Ruby you can create Base instances and they do the right thing. The problem occurs when you try to derive a new Ruby class from this extension module class and the argument list for the derived class' initialize method doesn't exactly match that for the base class, e.g. class Derived < Base def initialize(x, y) super @x, @y = x, y end end d = Derived.new(2.0, 3.0) This will cause an ArgumentError exception to be raised since you're passing two arguments (2.0, 3.0) into Base.new, which expects no arguments. The Solution ============ The correct solution is for SWIG to generate two different Ruby methods for each C++ class constructor it wraps. We still need a "new" singleton method, which would look something like this: static VALUE _wrap_new_Base(int argc, VALUE *argv, VALUE self) { VALUE vresult = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_Base, 1); rb_obj_call_init(vresult, argc, argv); return vresult; } but we'd also generate an initialize method, which would look something like this: static VALUE _wrap_Base_initialize(int argc, VALUE *argv, VALUE self) { Base *result; if ((argc < 0) || (argc > 0)) rb_raise(rb_eArgError, "wrong # of arguments(%d for 0)", argc); result = (Base *) new Base(); DATA_PTR(self) = result; return self; } This seems consistent with how most (non-SWIGged) Ruby extension modules handle Ruby's two-step object creation and initialization process. It doesn't quite fit SWIG's model of mapping a C++ constructor to exactly one wrapper function, but I've modified a local copy of SWIG to get the job done.