it-roy-ru.com

Почему прототипы функций Perl 5 плохие?

В еще один вопрос переполнения стекаЛеон Тиммерманс утверждал:

Я бы посоветовал вам не использовать прототипы. У них есть свои применения, но не в большинстве случаев и определенно не в этом.

Почему это может быть правдой (или иначе)? Я почти всегда поставляю прототипы для своих функций Perl, и я никогда прежде не видел, чтобы кто-то говорил что-то плохое об их использовании.

115
Alnitak

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

Прототипы позволяют вам определять функции, которые ведут себя как встроенные функции.

  • Скобки необязательны.
  • Контекст навязывается аргументам.

Например, вы можете определить функцию следующим образом:

sub mypush(\@@) { ... }

и назвать это как

mypush @array, 1, 2, 3;

без необходимости писать \, чтобы получить ссылку на массив.

Короче говоря, прототипы позволяют вам создавать свой собственный синтаксический сахар. Например, среда Moose использует их для эмуляции более типичного синтаксиса OO.

Это очень полезно, но прототипы очень ограничены:

  • Они должны быть видны во время компиляции.
  • Их можно обойти.
  • Распространение контекста на аргументы может вызвать неожиданное поведение.
  • Они могут затруднить вызов функций с использованием чего-либо, кроме строго предписанной формы.

Смотрите Prototypes в perlsub для всех подробностей.

120
Michael Carman

Проблема в том, что прототипы функций Perl не делают то, что думают люди. Их цель - позволить вам писать функции, которые будут анализироваться, как встроенные функции Perl.

Прежде всего, вызовы методов полностью игнорируют прототипы. Если вы занимаетесь программированием OO, не имеет значения, какой прототип есть у ваших методов. (Таким образом, у них не должно быть никакого прототипа.)

Во-вторых, прототипы не строго соблюдаются. Если вы вызываете подпрограмму с &function(...), прототип игнорируется. Таким образом, они не обеспечивают никакой безопасности.

В-третьих, они пугающие действия на расстоянии. (Особенно прототип $, который заставляет соответствующий параметр оцениваться в скалярном контексте вместо контекста списка по умолчанию.)

В частности, они затрудняют передачу параметров из массивов. Например:

my @array = qw(a b c);

foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);

sub foo ($;$$) { print "@_\n" }

foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);

печатает:

a b c
a b
a b c
3
b
a b c

наряду с 3 предупреждениями о main::foo() called too early to check prototype (если предупреждения включены). Проблема в том, что массив (или срез массива), вычисленный в скалярном контексте, возвращает длину массива.

Если вам нужно написать функцию, которая действует как встроенная, используйте прототип. В противном случае не используйте прототипы.

Примечание: Perl 6 будет иметь полностью обновленные и очень полезные прототипы. Этот ответ относится только к Perl 5.

68
cjm

Я согласен с вышеуказанными двумя постерами. В общем, следует избегать использования $. Прототипы полезны только при использовании аргументов блока (&), globs (*) или ссылочных прототипов (\@, \$, \%, \*)

30
Leon Timmermans

Некоторые люди, глядя на прототип подпрограммы Perl, думают, что это означает то, чего нет:

sub some_sub ($$) { ... }

Для Perl это означает, что парсер ожидает два аргумента. Это способ Perl позволять вам создавать подпрограммы, которые ведут себя как встроенные модули, и все они знают, чего ожидать от следующего кода. Вы можете прочитать о прототипах в perlsub

Не читая документацию, люди предполагают, что прототипы ссылаются на проверку аргументов во время выполнения или что-то подобное, что они видели в других языках. Как и большинство вещей, которые люди предполагают о Perl, они оказываются неправы.

Тем не менее, начиная с Perl v5.20, в Perl есть экспериментальная функция, которая написана мной, которая дает нечто большее, чем то, что пользователи ожидают и что. Perl подпрограмма подписи выполняет подсчет аргументов во время выполнения, назначение переменных и настройку по умолчанию:

use v5.20;
use feature qw(signatures);
no warnings qw(experimental::signatures);

animals( 'Buster', 'Nikki', 'Godzilla' );

sub animals ($cat, $dog, $lizard = 'Default reptile') { 
    say "The cat is $cat";
    say "The dog is $dog";
    say "The lizard is $lizard";
    }

Эта функция, вероятно, вам нужна, если вы рассматриваете прототипы.

4
brian d foy