Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

XSUBs with variable input types

by crenz (Priest)
on Oct 24, 2004 at 20:08 UTC ( #402061=perlquestion: print w/replies, xml ) Need Help??
crenz has asked for the wisdom of the Perl Monks concerning the following question:

I'm working on creating an OO-style interface to a procedural C API (Mac OS X' CoreMIDI, for the interested). I'm not really an XS expert, so I'd like some advice on one specific problem:

Let's assume we have a base class, foo. Classes baz and bar and other classes inherit from this class. The C API returns me opaque references to objects of these classes and offers several functions such as GetName that work with foo, bar and baz, but not with quux objects. So

n = GetName(aBarRef); n = GetName(aFooRef); n = GetName(aBazRef);
will all work correctly.

For the Perl interface, I want to create classes Foo, Bar and Baz. Now, if I create an XSUB GetName(fooRef myReference), Perl will complain if I call it with a barRef.

So the question is: How can I make an XSUB accept input parameters of a number of different types? Or should I just create different XSUBs (GetFooName, GetBarName, ...), since I'm not going to expose these functions to the user of my module anyway?

Replies are listed 'Best First'.
Re: XSUBs with variable input types
by thospel (Hermit) on Oct 24, 2004 at 22:15 UTC
    If at the perl level your Bar and Baz also inherit from Foo, the call will get accepted in fact. Now if at the C level calling getName will also work on e.g. bar objects even though they are currently in a foo typed variable, then all is fine (depends on how the C level inheritance is done, usually this would work).

    But even if it doesn't, you could always build your own polymorphic GetName by simply saying the argument is an SV * and determining the exact type by yourself with something like (untested):

    ... GetName(SV *thingy) PREINIT: IV tmp; CODE: if (sv_derived_from(thingy, "Foo")) { fooRef foo; tmp = SvIV((SV*) SvRV(thingy)); foo = INT2PTR(fooRef, tmp); getName(foo); } else if (sv_derived_from(thingy, "Bar")) { barRef bar; tmp = SvIV((SV*) SvRV(thingy)); bar = INT2PTR(barRef, tmp); getName(bar); } else if (sv_derived_from(thingy, "Baz")) { bazRef baz; tmp = SvIV((SV*) SvRV(thingy)); baz = INT2PTR(bazRef, tmp); getName(baz); } else croak("Some unhandled argument type message"); ...

    Doing it like that is not necessarily a good idea though. If Foo, Bar and Baz form the basis of separate object hierarchies at the perl level, it probably makes more sense to have a GetName for each object type in your XS code. No need to pollute the accessor name with the type though, just have them all in a different MODULE/PACKAGE section.

      Thanks for the hints! However, Perl can't know about the relationship with the Perl classes, since in my typemap, I declared the following:

      fooRef T_PTROBJ barRef T_PTROBJ bazRef T_PTROBJ

      How should I go about telling Perl that fooRef actually is a Foo object?

        Please read the section "Perl Objects And C Structures" in perlxs (ignore the part about "Ptr" getting appended). You probably want your typemap to say:
        and then have typedefs in your XS code to map these to your C level types. The perl level object hierarchy you define in the normal way in .pm files with e.g. things like:
        package Bar; ... use base qw(Foo); ...
        (and supposedly does the dynaload)

        Again, this last is not necessarily a good idea unless it's ok to call Foo functions on Bar objects for XS methods that exist in Foo but not in Bar (they will get called through inheritance if you apply that method to a Bar object)

Re: XSUBs with variable input types
by Joost (Canon) on Oct 24, 2004 at 21:03 UTC

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://402061]
Approved by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (4)
As of 2017-06-23 01:06 GMT
Find Nodes?
    Voting Booth?
    How many monitors do you use while coding?

    Results (533 votes). Check out past polls.