Почему прототипы функций Perl 5 плохи?
Вопрос
В еще один вопрос о переполнении стека Леон Тиммерманс утверждал:
Я бы посоветовал вам не использовать прототипы.У них есть свое применение, но не в большинстве случаев и уж точно не в этом.
Почему это может быть правдой (или иначе)?Я почти всегда предоставляю прототипы своих функций Perl и никогда раньше не видел, чтобы кто-нибудь говорил что-то плохое об их использовании.
Решение
Прототипы неплохие, если их правильно использовать.Трудность в том, что прототипы Perl работают не так, как от них часто ожидают люди.Люди, имеющие опыт работы с другими языками программирования, склонны ожидать, что прототипы предоставят механизм проверки правильности вызовов функций:то есть, что у них есть правильное количество и тип аргументов.Прототипы Perl не очень подходят для этой задачи.Это злоупотребление плохо.Прототипы Perl имеют единственную и совершенно разную цель:
Прототипы позволяют определять функции, которые ведут себя как встроенные функции.
- Круглые скобки необязательны.
- Контекст накладывается на аргументы.
Например, вы можете определить такую функцию:
sub mypush(\@@) { ... }
и назовите это как
mypush @array, 1, 2, 3;
без необходимости писать \
чтобы получить ссылку на массив.
Короче говоря, прототипы позволяют вам создавать свой собственный синтаксический сахар.Например, платформа Moose использует их для эмуляции более типичного объектно-ориентированного синтаксиса.
Это очень полезно, но прототипы очень ограничены:
- Они должны быть видимы во время компиляции.
- Их можно обойти.
- Распространение контекста на аргументы может привести к неожиданному поведению.
- Они могут затруднить вызов функций, используя что -либо, кроме строго предписанной формы.
Видеть Прототипы в perlsub для всех кровавых подробностей.
Другие советы
Проблема в том, что прототипы функций Perl не делают то, что думают люди.Их цель — дать вам возможность писать функции, которые будут анализироваться подобно встроенным функциям Perl.
Прежде всего, вызовы методов полностью игнорируют прототипы.Если вы занимаетесь объектно-ориентированным программированием, не имеет значения, какой прототип имеют ваши методы.(Поэтому у них не должно быть никакого прототипа.)
Во-вторых, прототипы не соблюдаются строго.Если вы вызываете подпрограмму с &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.
Я согласен с вышеуказанными двумя постерами. В общем, следует избегать использования $
. Прототипы полезны только при использовании аргументов блока ( & amp;
), глобусов ( *
) или ссылочных прототипов ( \ @
, \ $
, \%
, \ *
)
Некоторые люди, глядя на прототип подпрограммы 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";
}
Эта функция, вероятно, вам нужна, если вы рассматриваете прототипы.