Происхождение обескураженных идиом Perl: & x (...) и sub x ($$) {...} - PullRequest
4 голосов
/ 16 мая 2010

В моем Perl-коде я ранее использовал следующие два стиля написания, которые, как я обнаружил, в современном Perl не рекомендуется:

# Style #1: Using & before calling a user-defined subroutine
&name_of_subroutine($something, $something_else);

# Style #2: Using ($$) to show the number of arguments in a user-defined sub
sub name_of_subroutine($$) {
  # the body of a subroutine taking two arguments.
}

Поскольку я узнал, что эти стили не рекомендуются, я просто перестал их использовать.

Однако из любопытства хотелось бы знать следующее:

  • Каково происхождение этих двух стилей письма? (Уверен, я сам не придумал стили).
  • Почему эти два стиля написания не поощряются в современном Perl?
  • Были ли стили считаться лучшей практикой в ​​какой-то момент времени?

Ответы [ 3 ]

15 голосов
/ 16 мая 2010

Символ & обычно не используется с вызовами функций в современном Perl по двум причинам. Во-первых, это в значительной степени избыточно, так как Perl будет рассматривать функцию, которая выглядит как функция (за которой следует парамен). Во-вторых, существует большая разница между способами выполнения &function() и &function, что может сбивать с толку менее опытных программистов на Perl. В первом случае функция вызывается без аргументов. Во втором случае функция вызывается с текущим значением @_ (и она может даже вносить изменения в список аргументов, что будет видно в последующих операторах в этой области:

sub print_and_remove_first_arg {print 'first arg: ', shift, "\n"}

sub test {
   &print_and_remove_first_arg;

   print "remaining args: @_\n";
}

test 1, 2, 3;

печать

first arg: 1
remaining args: 2 3

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

Прототипы похожи, и их использование должно быть ограничено в современном Perl. Что следует четко указать, так это то, что прототипы в Perl НЕ являются сигнатурами функций. Они являются подсказками для компилятора, которые говорят ему анализировать вызовы этих функций аналогично встроенным функциям. То есть каждый из символов в прототипе указывает компилятору наложить этот тип контекста на аргумент. Эта функциональность может быть очень полезна при определении функций, которые ведут себя как map или push или keys, которые все обрабатывают свой первый аргумент иначе, чем стандартный оператор списка.

sub my_map (&@) {...}  # first arg is either a block or explicit code reference

my @ret = my_map {some_function($_)} 1 .. 10;

Причина sub ($$) {...} и подобного использования прототипов не приветствуется, потому что 9 раз из 10 автор имеет в виду «я хочу два аргумента», а не «я хочу два аргумента каждый со скалярным контекстом, наложенным на сайт вызова». Первое утверждение лучше написано:

use Carp;
sub needs2 {
   @_ == 2 or croak 'needs2 takes 2 arguments';
   ...
}

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

my @array = (2, 4);

needs2 @array;

Подводя итог, можно сказать, что и прототип & sigil и функция являются полезными и мощными инструментами, но их следует использовать только тогда, когда требуется эта функциональность. Их избыточное использование (или неправильное использование в качестве проверки аргументов) ведет к непреднамеренному поведению и затрудняет поиск ошибок.

3 голосов
/ 16 мая 2010

Функциональные вызовы & in были обязательными в Perl 4, так что, возможно, вы взяли это из программирования Perl (1991) Ларри Уолла и Рэндала Л. Шварца, как я, или где-то в этом роде.

Что касается прототипов функций, мое предположение менее квалифицированно. Может быть, вы имитировали языки, в которых есть смысл и / или обязательно объявлять списки аргументов, и, поскольку прототипы функций в Perl выглядят как списки аргументов, вы начали их добавлять?

& function не рекомендуется, потому что делает код менее читабельным и не обязательным (случаи, когда & function необходима, редки и часто лучше избегать).

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

& было обязательным в Perl 4, поэтому они были лучшей / необходимой практикой. Я не думаю, что функциональные прототипы когда-либо были.

1 голос
/ 16 мая 2010

Для стиля # 1 подпрограмма & before необходима только в том случае, если у вас есть подпрограмма, которая разделяет имя со встроенным, и вам необходимо определить, какое из них вы хотите вызвать, чтобы интерпретатор знал, что происходит. В противном случае это эквивалентно вызову подпрограммы без &.

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

Что касается прототипов функций, то они застряли в Perl по факту и на самом деле не делают того, для чего они были созданы. От статья на perl.com:

По большей части прототипы доставляют больше хлопот, чем стоят. Во-первых, Perl не проверяет прототипы на наличие методов, потому что для этого потребуется способность определять во время компиляции, какой класс будет обрабатывать метод. Потому что вы можете изменить @ISA во время выполнения - вы видите проблему. Основная причина, однако, в том, что прототипы не очень умные. Если вы укажете sub foo ($$$), вы не сможете передать ему массив из трех скаляров (это проблема с vec ()). Вместо этого вы должны сказать foo ($ x [0], $ x [1], $ x [2]), и это просто боль.

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

Для чего бы то ни было, Perl 6 добавляет формальные списки параметров к языку, подобному этому:

sub do_something(Str $thing, Int $other) {
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...