Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Re: Can't create XSUBs for C functions with a same name

by syphilis (Canon)
on Aug 23, 2012 at 00:29 UTC ( #989172=note: print w/ replies, xml ) Need Help??


in reply to Can't create XSUBs for C functions with a same name

There are two C functions called 'add'. One takes 2 arguments and the other takes 3 arguments

I would combine them into one function called add. Here's an Inline::C demo:

use warnings; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'EOC'; int add(SV * a, ...) { dXSARGS; int i, ret = 0; for(i = 0; i < items; i++) ret += SvIV(ST(i)); return ret; } EOC print add(11, 12), "\n"; # prints 23 print add(10, 11, 12), "\n"; # prints 33
In a nutshell, the ellipsis ('...') allows you to provide any number of arguments.
The 'items' variable (enabled by calling dXSARGS) tells you how many arguments the function received - and you design the function to do whatever it's supposed to do for that number of arguments.

Cheers,
Rob


Comment on Re: Can't create XSUBs for C functions with a same name
Download Code
Re^2: Can't create XSUBs for C functions with a same name
by Anonymous Monk on Aug 23, 2012 at 10:59 UTC
    Thanks for the idea, Rob. Indeed, I have a C++ code. Sorry about confusion. Here is what I came up with after all:
    int add(...) CODE: if (items == 2) RETVAL = add((int)SvIV(ST(0)), (int)SvIV(ST(1))); else RETVAL = add((int)SvIV(ST(0)), (int)SvIV(ST(1)), (int)SvIV(ST(2))) +; OUTPUT: RETVAL
    Although, I was hoping there was some XS trick to handle this situation in a more elegant way.
      Hmm, Wx created macros like MATCH_REDISP to manage dispatch based on args ... not sure if you consider that elegant. There is also ExtUtils::XSpp but its more of the same (and it doesn't include MATCH_REDISP)

      For what it's worth, Rob's code is also valid for C++ (and Inline::CPP):

      use strict; use warnings; use Inline CPP => Config => BUILD_NOISY => 1; use Inline CPP => <<'EOCPP'; int add(SV * a, ...) { dXSARGS; int i, ret = 0; for(i = 0; i < items; i++) ret += SvIV(ST(i)); return ret; } EOCPP print add(11, 12), "\n"; # prints 23 print add(10, 11, 12), "\n"; # prints 33

      ...outputs...

      23 33

      While that's still not the same as function overloading, It's actually one of the best (clearest) examples I've seen anywhere on how to use the "..." parameter. I might have to add it to Inline::CPP's POD on some future release.

      Another approach would be to use Inline::CPP, and wrap your functions in classes:

      use strict; use warnings; use Inline CPP => Config => BUILD_NOISY => 1; use Inline CPP => 'DATA'; my $foo = Foo->new(); my $bar = Bar->new(); sub add { if( @_ == 2 ) { return $foo->add(@_); } return $bar->add(@_); } __DATA__ __CPP__ struct Foo { add( int a, int b ) { return a + b; } }; struct Bar { add( int a, int b, int c ) { return a + b + c } };

      Of course with this process you're adding an additional Perl layer, so if your C++ subs are trivial, your performance will actually go down.

      As the POD for Inline::CPP states, the module enables a large subset of C++, but not all of C++. Function overloading is one of those "not all" areas.


      Dave

Re^2: Can't create XSUBs for C functions with a same name
by davido (Archbishop) on Aug 23, 2012 at 21:00 UTC

    Let's say the user has two (or more) functions that are overloaded (C++ obviously), and that it's not trivial to implement them as a single variable-parameter function. Obviously XS can't deal with overloaded functions -- it's just too much a C++ thing. But there is another hope, and one that's often used when using Inline::C or Inline::CPP to interface with external libraries: Write a wrapper function.

    Another limitation of Inline::CPP is that you can't expose templates directly to Perl. As with function overloading, Perl XS would have no idea what to do with template definitions. And C++ wouldn't know how Perl intends to call the functions, and thus wouldn't be able to expand the templates at compile-time. But once again, simple wrappers can easily hide templates from Perl/XS.

    Ok, we're not dealing with templates here... just overloading. Either way the following will work. Write a wrapper that accepts a variable argument list, and then dispatches a call to the overloaded functions based on how many args are provided. It's a little cumbersome once you get more than a handful of variations to deal with, but I don't think people generally create more than a handful of overloads anyway (they just turn to templates, which is why I mentioned templates earlier).

    So here's a hybrid: The overloaded functions (which won't bind to Perl), and the wrapper (which will):

    use strict; use warnings; use v5.16; use Inline CPP => 'DATA'; say multiadd( 1 ); # No dispatch; just return the value. say multiadd( 1, 2 ); # Dispatch add( int, int ). say multiadd( 1, 2, 3 ); # Dispatch add( int, int, int ). say multiadd( 1, 2, 3, 4 ); # No dispatch; throw an exception. __DATA__ __CPP__ #include <stdexcept> // Overloaded functions: add(int,int), add(int,int,int): No (reliable* +) Perl binding. int add ( int a, int b ) { return a + b; } int add ( int a, int b, int c ) { return a + b + c; } // XS binding will be generated for multiadd(). int multiadd ( SV * a, ... ) { dXSARGS; try{ switch ( items ) { case 1: return SvIV(ST(0)); case 2: return add( SvIV(ST(0)), SvIV(ST(1)) ); case 3: return add( SvIV(ST(0)), SvIV(ST(1)), SvIV(ST(2)) ); default: throw std::runtime_error( "multiadd() - Too many args in function call" ); } } catch ( std::runtime_error msg ) { croak( msg.what() ); // Perl wants exceptions via croak. } }

    This same approach could be used to dispatch calls based on any function signature criteria; number of parameters, or data-types. Additionally, a similar approach works for dispatching to template-generated functions or classes.

    *(reliable): I think the last overload defined will bind via XS, but the others will be masked. It's not worth even trying to call directly.


    Dave

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://989172]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (12)
As of 2014-07-25 07:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (169 votes), past polls