In my XS file I have:
As my new method:
matrix *
matrix::new( size_t ncols, size_t nrows )
which returns a matrix
object like it should and I can invoke methods.
Then I have a method call which creates a new matrix object and is supposed to return it as a new matrix:
matrix *
matrix::getInnerMatrix( )
PREINIT:
char * CLASS = (char *)SvPV_nolen(ST(0));
CODE:
RETVAL = static_cast<matrix*>(THIS->matrix::getInnerMatrix());
OUTPUT:
RETVAL
However the returned type is matrix=SCALAR(0x122f81c)
and therefore I am unable to invoke any method calls from this object as the perl interpreter seems to be viewing the returned type as a scalar value type instead of a 'matrix' object. Here is a test script:
$m1 = matrix::new(matrix,4,4);
@arr = ( 1 .. 16 );
$aref = [@arr];
$m1->assign_aref($aref);
my $m2 = $m1->getInnerMatrix();
print ref $m1; # returns "matrix" (like it should)
print "\n\n";
print ref $m2; # returns "matrix=SCALAR(0x122f81c)" (wrong)
Here is my typemap:
TYPEMAP
matrix * O_MATRIX
OUTPUT
O_MATRIX
sv_setref_pv( $arg, CLASS, (void*)$var );
INPUT
O_MATRIX
if ( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) {
$var = ($type)SvIV((SV*)SvRV( $arg ));
}
else {
warn( \"${Package}::$func_name() -- ${var} not a blessed SV reference\" );
XSRETURN_UNDEF;
}
What changes must I make in my XS file, or any other file to ensure that a pure matrix
object is returned?
When using XS with C++, the XS preprocessor inserts THIS
for instance methods and CLASS
for static methods. A method called new
is treated as a static method. This allows the resulting xsubs to be used as instance methods/class methods by default: matrix->new
and $m->getInnerMatrix()
.
Your typemap uses the CLASS
variable which is not provided for instance methods. In your case, I would hard-code the package name in the type map instead:
OUTPUT
O_MATRIX
sv_setref_pv( $arg, "matrix", (void*)$var );
The typemap is also used when an argument of that type is not used as the invocant. E.g. consider this xsub:
matrix*
some_other_xsub(x)
int x
Here there would not by a CLASS
variable for the matrix*
return value either.
Note that lowercase package names should only be used for pragma packages (like strict
or warnings
). Please use CamelCase for your classes.
Your attempt to provide your own value for CLASS
failed because SvPV_nolen()
stringifies the reference and does not get the reference type. I.e. it's equivalent to "$m"
, not to ref $m
. A more correct alternative would have been to use sv_ref()
:
char* CLASS = SvPV_nolen(sv_ref(NULL, THIS, true));
The third parameter to sv_ref()
makes this function work like the Perl function ref
, i.e. return the class name if the scalar is blessed, not just the underlying reference type.