Последнее в категории Стиль кода

О кавычках

| Нет комментариев

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

С одной стороны, если всегда писать двойные кавычки, то не придется судорожно отлаживать изменения, когда дописываешь к строке переменную или перевод строки, а получаешь код $var\n на выводе.

С другой стороны, одинарные кавычки спасут от опечатки (или копипейста). Сегодня я решил поправить код пятилетней давности и добавить возможность редактировать заголовок темы на форуме.

Написал «безопасный» SQL-запрос:

my $sth = $dbh->prepare("
    update
        thread
    set
        title = ?
    where
        $thread_id = ?
");
$sth->execute($title, $thread_id);

То, что поле в таблице называется id, а не thread_id, не важно: MySQL не сообщила об ошибке, а спокойно проинтерпретировала интерполированную строку с подставленным значением "...where 8899 = 8899", обновив все заголовки во всей таблице. 

({}) vs. ()

| 1 комментарий

Сколько существует YAPC::TV, столько существует и небольшой вспомогательный скрипт, который автоматизирует работу по конвертированию видеофайлов в разные форматы.

В этой программе есть функция convert, которая принимает ссылку на хеш:

sub convert {
    my $param = shift;

И затем разыменовывает ее:

my $s = "-s $$param{s}" if $$param{s};

При этом каждый вызов convert содержит обилие скобок — одни для вызова функции, другие для создания анонимного хеша:

convert({
    type => 'mpg',
    s => '480x270',
    r => 25,
    b => '512kb',
    ar => 22050,
});

Конечно, можно было бы вторые скобки не ставить вообще, а в функции принимать готовый хеш:

sub convert {
    my %param = @_;

Но тут возникает вопрос о том, как этому научить начинающего программиста. Конструкции вида %hash = @array не так просто понять в начале изучения языка, как это кажется после нескольких лет использования перла.

Хотя различие между следующими двумя строками схватывается на ура:

$a = @a;
($a) = @a;

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

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

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

Другой пример — требуется предоставить демонстрационную версию программы.

Простое решение, для которого даже не потребуется установки никаких дополнительных утилит, — воспользоваться препроцессором С. Компилятор gcc не в счет: он наверняка уже установлен в системе.

package My::Module;
. . .
#ifdef DEMO_MODE
say rand(10);
#else
say $this->real_method();
#endif
. . .

Еще один пример предложенного подхода — эмуляция встроенной функции say, если потребуется развернуть приложение, в котором из возможностей версии 5.10 используется только say, на сервере со старым перлом:

#ifndef SAY
sub say {
   print @_, "\n";
}
#endif

Все, что требуется для того, чтобы на основании таких заготовок получить код для передачи, — запустить препроцессор C:

$ gcc -DDEMO_MODE -E mymodule.pm.c > mymodule.pm

Точка с запятой в перле необязательна, если она приходится на конец блока:

sub doit {
    say 123
}

В отличие от, например, C++, где аналогичная конструкция вызовет ошибку компиляции:

int main() {
   return 0
}

s.cpp: In function 'int main()':
s.cpp:3: error: expected ';' before '}' token

Различие здесь в том, чем точка с запятой является с точки зрения языка. В перле это разделитель инструкций, в C++ — признак окончания выражения.

В JavaScript ситуация еще интереснее: там точки с запятой допустимо опускать не только в конце блока, но и в конце строки:

x += id.value
alert(x)

При этом разрешено продолжать выражение на следующей строке:

x +=
   id.value
alert(x)

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

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

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

sub add {
    my ($a, $b) = @_;
    $a + $b
}

Результат выражения $a + $b — последнее значение, вычисленное в теле подпрограммы — считается результатом, который и нужно передать вызывающему коду.

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

Ситуация очень похожа на рекомендацию ставить запятую после последнего элемента при объявлении хеша:

my %x = (
    alpha => 'a',
    beta => 'b',
);

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

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

sub add {
    my ($a, $b) = @_;
    $a + $b
    warn $a;
}

Даже на время отладки не хочется искажать написанный ранее код, поэтому пропущенная точка с запятой просится в начало строки:

sub add {
    my ($a, $b) = @_;
    $a + $b
;    warn $a;
}

Такие трюки с пропущенной запятой — один из приемов, которые малыми шажками ведут код к read-only-модели.

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

sub add {
    shift() + shift
}

Но лучше так не делать. Или только ради развлечения и изучения возможностей языка.

Страницы

  • img

Об архиве

Эта страница содержит последние записи категории Стиль кода.

Предыдущая категория — Сообщество.

Следующая категория — Тесты.

Смотрите новые записи на главной странице или загляните в архив, где есть ссылки на все сообщения.