Почему Perl :: Critic не любит использовать shift для заполнения переменных подпрограммы?

В последнее время я решил чаще использовать Perl :: Critic на моем код. После программирования на Perl в течение почти 7 лет я привык к большинству лучших практик Perl на долгое время, но я знаю, что всегда есть возможности для улучшения. Однако меня беспокоит то, что Perl :: Critic не Мне не нравится, как я распаковываю @_ для подпрограмм. Например:

sub my_way_to_unpack {
    my $variable1 = shift @_;
    my $variable2 = shift @_;

    my $result = $variable1 + $variable2;
    return $result;
}

Я всегда так поступал, и, как это обсуждалось как в PerlMonks, так и в Stack Overflow, это тоже не обязательно зло.

Изменение приведенного выше фрагмента кода на ...

sub perl_critics_way_to_unpack {
    my ($variable1, $variable2) = @_;

    my $result = $variable1 + $variable2;
    return $result;
}

... тоже работает, но мне труднее читать. Я также прочитал книгу Дамиана Конвея Perl Best Practices, и я не совсем понимаю, как мой предпочтительный подход Распаковка подпадает под его предложение избегать прямого использования @_, поскольку Perl :: Critic подразумевает. Мне всегда казалось, что Конвей говорил о таких мерзостях, как:

sub not_unpacking {
    my $result = $_[0] + $_[1];
    return $result;
}

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

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

Будет ли это то, что, по мнению других людей, следует поднять с помощью Perl :: Critic сопровождающие?


person Weegee    schedule 16.02.2010    source источник
comment
На первый взгляд Perl :: Critic не нравится, потому что он работает с использованием магии, например, shift работает с @_, когда не указана никакая переменная. Однако было бы полезно узнать, какое правило Perl :: Critic хочет это изменить.   -  person Powerlord    schedule 16.02.2010
comment
Кстати, если вы используете списковую форму назначения, Komodo Edit / IDE может сообщить вам аргументы подпрограммы.   -  person Brad Gilbert    schedule 16.02.2010
comment
Спасибо, Брэд, я этого не осознавал. Я старый пользователь ViM, поэтому обычно я игнорирую то, что Komodo Edit ставит передо мной, но мне всегда было интересно, как это работает.   -  person Weegee    schedule 16.02.2010
comment
Даже под --brutal я не получаю никаких жалоб на распаковку аргументов для вашего примера кода. Какую версию Perl :: Critic вы используете? (Я использую 1.105)   -  person Michael Carman    schedule 17.02.2010
comment
Отличный улов Майкл. Собственно, я собираюсь подтвердить, когда вернусь к работе завтра, но сдвиг подходит для Perl :: Critic 1.105, а сдвиг @_ - нет. Завтра я отправлю отчет об этой ошибке.   -  person Weegee    schedule 17.02.2010
comment
Назначение списка труднее читать, потому что вы еще не привыкли к нему. Дай этому шанс. :)   -  person brian d foy    schedule 22.02.2010


Ответы (5)


Ответ прост: Perl :: Critic здесь не следует за PBP. В книге прямо говорится, что идиома сдвига не только приемлема, но и предпочтительна в некоторых случаях.

person PBP reader    schedule 16.02.2010

Запуск perlcritic с --verbose 11 объясняет политики. Однако не похоже, что ни одно из этих объяснений относится к вам.

Always unpack @_ first at line 1, near 
'sub xxx{ my $aaa= shift; my ($bbb,$ccc) = @_;}'.
  Subroutines::RequireArgUnpacking (Severity: 4)
    Subroutines that use `@_' directly instead of unpacking the arguments to
    local variables first have two major problems. First, they are very hard
    to read. If you're going to refer to your variables by number instead of
    by name, you may as well be writing assembler code! Second, `@_'
    contains aliases to the original variables! If you modify the contents
    of a `@_' entry, then you are modifying the variable outside of your
    subroutine. For example:

       sub print_local_var_plus_one {
           my ($var) = @_;
           print ++$var;
       }
       sub print_var_plus_one {
           print ++$_[0];
       }

       my $x = 2;
       print_local_var_plus_one($x); # prints "3", $x is still 2
       print_var_plus_one($x);       # prints "3", $x is now 3 !
       print $x;                     # prints "3"

    This is spooky action-at-a-distance and is very hard to debug if it's
    not intentional and well-documented (like `chop' or `chomp').

    An exception is made for the usual delegation idiom
    `$object->SUPER::something( @_ )'. Only `SUPER::' and `NEXT::' are
    recognized (though this is configurable) and the argument list for the
    delegate must consist only of `( @_ )'.
person mob    schedule 16.02.2010
comment
Ни то, ни другое, поэтому меня беспокоит, правильно ли Perl :: Critic проверяет случай Всегда распаковывать @_ ... - person Weegee; 16.02.2010

Важно помнить, что многие материалы в Perl Best Practices - это всего лишь мнение одного человека о том, что выглядит лучший или самый простой в использовании, и неважно, сделаете ли вы это по-другому. Об этом Дамиан говорит во вступительном тексте к книге. Нельзя сказать, что это все - в этом есть много абсолютно важных вещей: например, использование strict.

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

Я стараюсь следить за большинством вещей в PBP, но у Дамиана могут быть мои подпрограммы-аргументы shift и мои unless, когда он вырывает их из моих холодных мертвых кончиков пальцев.

Что касается Critic, вы можете выбрать, какие политики вы хотите применять, и даже создать свои собственные, если они еще не существуют.

person friedo    schedule 16.02.2010
comment
Это отличный момент, и я согласен с ним, но меня беспокоит то, правильно ли Perl :: Critic в своем состоянии по умолчанию говорит, что использование сдвига аргументов подпрограммы - это плохо. - person Weegee; 16.02.2010

В некоторых случаях Perl :: Critic не может точно обеспечить соблюдение руководящих принципов PBP, поэтому он может обеспечить приближение, которое пытается соответствовать духу руководящих принципов Конвея. И вполне возможно, что мы неверно истолковали или неправильно применили PBP. Если вы обнаружите что-то, что плохо пахнет, отправьте сообщение об ошибке по адресу [email protected], и мы сразу же рассмотрим его.

Спасибо,

-Джефф

person Jeffrey Thalhammer    schedule 17.02.2010
comment
Спасибо, что разместил здесь Джеффа. Завтра я отправлю электронное письмо на адрес электронной почты [email protected] о своих проблемах. Я вернулся и перечитал Раздел 9.3 в книге Конвея, и он даже заявляет: «В качестве альтернативы вы можете использовать серию отдельных вызовов смены в качестве первого« абзаца »подпрограммы. - person Weegee; 17.02.2010

Я думаю, вам следует избегать переключения передач, если в этом нет необходимости!

Просто наткнулся на такой код:

sub way {
  my $file = shift;
  if (!$file) {
    $file = 'newfile';
  }
  my $target = shift;
  my $options = shift;
}

Если вы начнете что-то менять в этом коде, есть большая вероятность, что вы случайно измените порядок смен или, возможно, пропустите одну, и все пойдет на юг. Кроме того, его трудно читать - потому что вы не можете быть уверены, что действительно видите все параметры для подпрограммы, потому что некоторые строки ниже могут быть где-то еще одним сдвигом ... И если вы используете некоторые регулярные выражения между ними, они могут заменить содержимое $ _ и начинают происходить странные вещи ...

Прямым преимуществом использования распаковки my (...) = @_ является то, что вы можете просто скопировать часть (...) и вставить ее туда, где вы вызываете метод, и иметь красивую подпись :) вы даже можете использовать ту же переменную - имена заранее и ничего менять не надо!

Я думаю, что сдвиг подразумевает операции со списком, где длина списка является динамической, и вы хотите обрабатывать его элементы по одному или когда вам явно нужен список без первого элемента. Но если вы просто хотите назначить весь список параметрам x, ваш код должен указать это с помощью my (...) = @_; никому не нужно удивляться.

person Falco    schedule 24.01.2014