Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Procedural and object oriented interface in Perl/XS

Tags:

perl

xs

I am currently writing my first XS-module (just a wrapper around the C math-library) with ok-ish success. The biggest issue is the documentation that is quite hard to understand and/or is incomplete.

I have successfully written a constructor in XS and implemented some functions out of the library as method calls. That works fine.

Now I want to implement a procedural interface, too. For this reason I need to know if its a method call or not. If its a method call the number to compute with the function is stored in the instance, if its a procedural call to a function its a number given as the first argument. This is the current code for the cosine-function:

double
cos(...)
    CODE:
        SV *arg = newSVsv(ST(0));
        if (sv_isobject(arg)) {
            HV *self_hv = MUTABLE_HV(SvRV(arg));
            SV **callback_ptr = hv_fetchs(self_hv, "Number", 0);
            SV *zahl = *callback_ptr;
        }
        else {
            SV *zahl = newSVnv(arg);
        }

        double x = SvNV(zahl);
        RETVAL = cos(x);
    OUTPUT:
        RETVAL
like image 280
user2875983 Avatar asked Apr 13 '26 21:04

user2875983


1 Answers

Generally speaking, writing subs which are intended to be called as either methods or functions is a bad idea. There are one or two well known modules that do this (CGI.pm springs to mind), but for the most part this is confusing for end users, and unnecessarily complicates your own code. Nobody will thank you for it. Pick one style and stick with it.

Let's assume you've chosen to stick with OO programming. Then, once your module is working and tested, you can write a second module, offering exportable functions instead of an OO interface. The second module can probably be written in plain old Perl, just acting as a wrapper around your OO module.

As an example, using pure Perl (and not XS) for readability:

use v5.14;

package MyStuff::Maths::OO {
   use Class::Tiny qw(number);
   sub cosine {
      my $self   = shift;
      my $number = $self->number;
      ...;
      return $cosine;
   }
}

package MyStuff::Maths::Functional {
   use Exporter::Shiny qw(cosine);
   sub cosine {
      my $obj = ref($_[0]) ? $_[0] : MyStuff::Maths::OO->new(number => $_[0]);
      return $obj->cosine;
   }
}

Now end users can choose to use your OO interface like this:

use v5.14;
use MyStuff::Maths::OO;

my $obj = MyStuff::Maths::OO->new(number => 0.5);
say $obj->cosine;

Or use the functional interface:

use v5.14;
use MyStuff::Maths::Functional -all;

say cosine(0.5);
like image 181
tobyink Avatar answered Apr 16 '26 01:04

tobyink



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!