Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

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

by Anonymous Monk
on Aug 22, 2012 at 22:37 UTC ( #989162=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks! I have been experimenting with XS and run into a little problem. There are two C functions called 'add'. One takes 2 arguments and the other takes 3 arguments:
int add(int a, int b) int add(int a, int b, int c)
I am trying to wrap them up in XS. But I am getting a redefinition error from a C compiler if I try the following code:
int add (int a, int b) int add (int a, int b, int c)
Obviously, the xsubpp does not take into account the different function signatures when it produces a C code. What should I do?

Comment on Can't create XSUBs for C functions with a same name
Select or Download Code
Re: Can't create XSUBs for C functions with a same name
by chromatic (Archbishop) on Aug 22, 2012 at 23:16 UTC
    What should I do?

    Use different names for these functions. C doesn't support what you're trying to do.

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

    C doesn't have function overloading. You're probably looking at C++ code. Unfortunately, even if you compile that code using something like Inline::CPP you're going to have to use different function names in some way, because XS, which is built on C, won't be able to bind two functions in the same namespace with the same name.

    use strict; use warnings; use Inline CPP => 'DATA'; print add( 1, 1 ), "\n"; print add( 1, 1, 1 ), "\n"; __DATA__ __CPP__ int add ( int a, int b ) { return a + b; } int add( int a, int b, int c ) { return a + b + c; }

    ...outputs...

    Usage: main::add(a, b, c) at ./mytest.pl line 7.

    ...where line 7 is the add( 1, 1 ) call.

    Perl can't be expected to understand C++'s rules for resolving overloading. And since Perl is a dynamic language, the C or C++ linker can't make the decision either.


    Dave

Re: Can't create XSUBs for C functions with a same name
by syphilis (Canon) on Aug 23, 2012 at 00:29 UTC
    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
      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

      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

Re: Can't create XSUBs for C functions with a same name
by BrowserUk (Pope) on Aug 23, 2012 at 00:48 UTC
    What should I do?
    1. With some levity, but a serious point if applicable:

      Define a single add() function that takes an arbitrary number of integers

      Best example I know of Variable argument lists.

    2. Put your similarly named functions/methods into different namespaces (Ie. packages).

      See The PACKAGE keyword.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (7)
As of 2014-12-20 23:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (99 votes), past polls