Процедурный и объектно-ориентированный интерфейс в Perl/XS

В настоящее время я пишу свой первый XS-модуль (просто оболочка вокруг математической библиотеки C) с хорошим успехом. Самой большой проблемой является документация, которую довольно сложно понять и/или которая является неполной.

Я успешно написал конструктор в XS и реализовал некоторые функции из библиотеки как вызовы методов. Это прекрасно работает.

Теперь я тоже хочу реализовать процедурный интерфейс. По этой причине мне нужно знать, является ли это вызовом метода или нет. Если это вызов метода, число для вычисления с помощью функции хранится в экземпляре, если это процедурный вызов функции, то число, указанное в качестве первого аргумента. Это текущий код функции косинуса:

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

person user2875983    schedule 23.10.2014    source источник
comment
Вы, кажется, забыли задать вопрос. Вы даже не намекнули на проблему. Что ты хочешь?   -  person ikegami    schedule 23.10.2014
comment
Примечание. Вы используете ST(0), не проверяя количество полученных аргументов.   -  person ikegami    schedule 23.10.2014
comment
Моя проблема: когда я вызываю его как метод без блока if и всего остального, он работает. Итак, я думаю, моя проблема где-то в условии if. Примечание: код даже не компилируется, он выдает ошибку в строке с назначением двойника (первый раз используется, но не объявлен, поэтому я предположил, что здесь проблема должна быть в условии if)   -  person user2875983    schedule 24.10.2014
comment
Во-первых, вы не упомянули об ошибке. Теперь, вы не упоминаете, что это такое? Мы не можем читать ваши мысли (или ваш экран)!   -  person ikegami    schedule 24.10.2014


Ответы (2)


Вообще говоря, написание подпрограмм, предназначенных для вызова как методов или функций, является плохой идеей. Есть один или два хорошо известных модуля, которые делают это (на ум приходит CGI.pm), но по большей части это сбивает с толку конечных пользователей и излишне усложняет ваш собственный код. Никто не скажет вам за это спасибо. Выберите один стиль и придерживайтесь его.

Предположим, вы решили придерживаться объектно-ориентированного программирования. Затем, когда ваш модуль заработает и протестирован, вы можете написать второй модуль, предлагающий экспортируемые функции вместо объектно-ориентированного интерфейса. Второй модуль, вероятно, можно написать на простом старом Perl, просто выступая в качестве оболочки вокруг вашего объектно-ориентированного модуля.

В качестве примера, используя чистый Perl (а не XS) для удобства чтения:

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;
   }
}

Теперь конечные пользователи могут использовать ваш объектно-ориентированный интерфейс следующим образом:

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

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

Или воспользуйтесь функциональным интерфейсом:

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

say cosine(0.5);
person tobyink    schedule 23.10.2014
comment
Я понимаю вашу точку зрения. В общем, я бы тоже так сделал. Но я начал работать над этой конкретной вещью, чтобы узнать о XS. Так что не было смысла писать обертку на обычном Perl. - person user2875983; 23.10.2014
comment
@ user2875983, На самом деле, это больше, чем вы думаете. Если вы хотите научиться использовать XS, то изучение того, что следует делать на стороне Perl, а что нет, будет полезным уроком. - person ikegami; 23.10.2014
comment
@ user2875983, ничто не мешает вам также написать оболочку в XS, если вы того пожелаете. В этом было бы мало преимуществ, кроме прироста скорости. Моя главная мысль заключается в том, что разделение этих двух интерфейсов на два модуля сохранит ваше здравомыслие, а также здравомыслие ваших конечных пользователей. Это то же самое, пишете ли вы XS или чистый Perl. - person tobyink; 24.10.2014

В моем случае это была простая проблема, и я просто не видел ее. Декларация SV *zahl внутри оператора if-else была проблемой. Предварительное объявление перед if было ключом к решению.

Но я согласен с решением tobyinks для модулей, которые используются другими людьми или где-то публикуются.

person user2875983    schedule 24.10.2014