Process and object-oriented interface in Perl / XS

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

I have successfully written a constructor in XS and implemented some functions from the library as method calls. This works great.

Now I also want to implement a procedural interface. For this reason, I need to know if its method is called or not. If its method calls a number to be calculated by a function, it is stored in the instance if its function call has a number specified 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

      

+3


source to share


2 answers


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

Let's say you decide to stick with OO programming. Then, once your module is running and tested, you can write a second module offering exported functions instead of an OO interface. The second module can probably be written in plain old Perl by simply acting as a wrapper around your OO module.

As an example, using pure Perl (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;
   }
}

      



End users can now 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 a functional interface:

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

say cosine(0.5);

      

+4


source


In my case, it was a simple problem and I just didn't see it. The problem with SV * zahl inside the if-else statement was the problem. The preceding before was the key to the solution.



But I agree with tobyinks solution for modules that are used by other people or published somewhere.

0


source







All Articles