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

Я видел запутанный и играющий в гольф код, который держится, чтобы не объявлять переменные, и я вижу, как пропустить их в командной строке с помощью ключа -e, чтобы уменьшить однострочный шрифт. Каковы случаи, когда вы не хотели бы use strict и/или use warnings в производственном коде?. Какими причинами вы не хотели бы их использовать?

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

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

Ответ 1

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

Прагма strict имеет три категории:

  • "vars" Заставляет вас объявлять все ваши переменные. Это защищает от опечаток и гарантирует, что вы выберете область действия (глобальную/лексическую). В однострочном пространстве это не так необходимо, поскольку, как правило, очень мало областей и очень мало переменных. Некоторые одноязычные идиомы не будут работать только с лексическими переменными.

  • "refs" запрещает symrefs. Они не имеют смысла с лексическими переменными, а Perl5 имеет реальные ссылки. Поэтому они вообще бесполезны. Тем не менее, symrefs остаются ценными для метапрограммирования:

    # generate accessors
    for my $field (qw/foo bar baz/) {
      no strict 'refs';
      *{ __PACKAGE__ . '::' . $field } = sub { shift()->{$field} };
    }
    
  • "subs" заставляет интерпретировать большинство простых слов как вызовы подпрограмм. Это устраняет двусмысленность foo . "bar" как foo() . "bar". Если эта категория не активирована, и если в настоящее время не определено значение foo, то оно будет анализироваться как "foo" . "bar". Это имеет смысл для программиста оболочки, где все слова являются строками. Но в программе Perl это значительно увеличивает когнитивную нагрузку программиста и не стоит того.

Сводка: для простых скриптов, которые не оптимизируются для чтения, strict "vars" на самом деле не обязательно. Есть несколько случаев, когда требуется no strict 'refs'.

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

my %hash = { foo => 1, bar => 2 };

и задайтесь вопросом, откуда взялся этот ключ HASH(0x1234567). Желательно, даже если вы используете однострочный вкладыш, за исключением случаев, когда вы используете строение undef и т.д.

В профессиональной кодовой базе нет оправдания для того, чтобы не использовать warnings всюду. Если предупреждение script предупреждает, что, скорее всего, есть ошибка, а no warnings не устраняет эту ошибку. Ваши знания о Perl никогда не столь обширны, как у прагмы warnings. Даже гуру ошибаются. use warnings - отличный отладочный ярлык.

Тем не менее, при развертывании программы может быть просто комментировать use warnings. Но никогда не для развития.

В зависимости от консенсуса в команде разработчиков также должны использоваться другие прагмы:

  • no indirect запрещает вызовы метода lathed new Foo. Я видела ошибки, которые можно было поймать во время компиляции с этой прагмой.
  • no autovivification предотвращает появление ссылок на операции только для чтения, такие как $hash{doesnt_exist}{foo}.

Ответ 2

Иногда strict и warnings мешают вам делать то, что вы хотите сделать, например, делать определенные манипуляции в таблице символов, которые будут нарушать strict 'refs', или переопределить подпрограмму, в которой будет срабатывать warnings 'redefine'. В других случаях более удобно игнорировать определенные предупреждения, чем писать защитный код против них, например, быстрый и грязный дамп базы данных для таблицы, которая может содержать значения NULL/undef, которые будут запускать warnings 'uninitialized'.

use strict и use warnings, а их замедлители no strict и no warnings могут быть локально локализованы, поэтому лучше всего отключить strict и warnings в наименьшей практической области.

@data = get_some_data_from_database();
if (some_condition()) {
    no warnings 'uninitialized';
    logger->debug("database contains: @$_") for @data;

    ## otherwise, suppressing the warnings would take something
    ## less readable and more error-prone like:
    #  logger->debug("database contains: @{[map{defined?$_:''}@$_]}") for @data
    #  logger->debug("database contains: @{[map{$_//''}@$_]}") for @data
}
# end of scope, warnings `uninitialized' is enabled again

Ответ 3

Выполнение use strict и use warnings помогает кому-то точно понять, что делает Perl.

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

Есть и другие веские причины:

  • экспериментирование с поведением, которое приведет к предупреждению о том, что вы уже полностью осознаете (например, много рекурсии)
  • с использованием старых пакетов (хотя любой из моих пакетов, написанных после июля 2000 года, по-прежнему не генерирует сообщений с use strict или use warnings, поэтому "старый" здесь означает действительно, действительно старый, например Perl версии 4 или старше)
  • когда вы хотите воспользоваться магическим поведением Perl, которого никто не ожидал бы (но который вы ожидаете, потому что вы эксперт) и не хотите платить цену за предупреждение за это

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

Обновление: @mob делает заявку в комментарии, которая имеет некоторое исследование, то есть, что не использование строгих и предупреждений - это микро-оптимизация ниже точки даже средних незначительных микроптимизаций. В каждом случае ниже реальное время для не использования строгих и предупреждений составляет 12 миллисекунд, и в каждом случае ниже реальное время их использования составляет 57 миллисекунд или более.

Таким образом, как я уже сказал, это возможное преимущество во время исполнения (что будет иметь значение, если вы делаете что-то вроде встраивания скриптов Perl в шаблоны и запускаете 10 или 20 из них за раз каждый раз, когда веб-страница был загружен, например), но по-прежнему рекомендуется использовать их, если вы точно не знаете, что делает Perl и почему, все время. Мое описание этой категории "экспертов" должно быть очень близко к пустому набору. Если вы считаете, что попадаете в эту категорию, вы автоматически этого не делаете.

[[email protected] ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.005s
sys     0m0.007s
[[email protected] ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.010s
sys     0m0.005s
[[email protected] ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.011s
sys     0m0.001s
[[email protected] ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.004s
sys     0m0.007s
[[email protected] ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.005s
sys     0m0.007s
[[email protected] ~]$ time perl -e 'use strict; use warnings;'

real    0m0.058s
user    0m0.058s
sys     0m0.000s
[[email protected] ~]$ time perl -e 'use strict; use warnings;'

real    0m0.057s
user    0m0.041s
sys     0m0.016s
[[email protected] ~]$ time perl -e 'use strict; use warnings;'

real    0m0.057s
user    0m0.033s
sys     0m0.025s
[[email protected] ~]$ time perl -e 'use strict; use warnings;'

real    0m0.057s
user    0m0.050s
sys     0m0.009s