Pull to refresh

Comments 41

С таким заголовком можно попасть в черный список Роскомнадзора. Будьте осторожны (с) Паблик Хабра
На всякий случай написал в хабрасуппорт, если что переименую.
Вроде появилась надежда что проблем не будет :) Не хотелось бы отдавать столько распространённую идиому Роскомнадзору без боя.
У надзирающих товарищей, с чувством юмора совсем плохо.
Ну а вы не стреляйте себе в ногу. Сделайте вот так, и будет вам счастье и радость:

mysub(@$x && $x->[0] =~ /abc/, $x = []);

В любом случае гораздо более осмысленно проверять не только ссылку на массив, но чтобы этот массив ещё и не был пустым.
Гхм, ну хотя это не работает с включенной прагмой strict.
Тогда, рез уж автовивификация есть, проверка на истинность $x вообще не нужна, и можно сразу проверять значение нулевого элемента:

mysub($x->[0] =~ /abc/, $x = []);
Если бы я знал изначально, что присутствуют все обстоятельства, описанные в статье, то конечно нашёл бы workaround (их можно много придумать). Тут основная фика как раз не вляпаться в такие «обстоятельства».
Хм-м, но всё же, если вы хотите придерживаться своей изначальной логики, то вот такая вот конструкция уж точно спасёт отца русской демократии:

mysub($x && $x->[0] =~ /abc/ || undef, $x = []);

P.S. Извиняюсь за флуд :-)
Или так
mysub(!! ($x && $x->[0] =~ /abc/) , $x = []);


Я один не понимаю, зачем вы используете прототипы аргументов для процедур?

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

use strict;
use warnings;
sub mysub
{
    my ($a, $b) = @_;
    print "a: $a\n";
    print "b: $b\n";
}
my $x = [];
mysub( ($x && ($x->[0] =~ /abc/i)), "some text $x->[0]" );


выдаёт

a: some text 
b: 


use strict;
use warnings;
sub mysub($$)
{
    my ($a, $b) = @_;
    print "a: $a\n";
    print "b: $b\n";
}
my $x = [];
mysub( ($x && ($x->[0] =~ /abc/i)), "some text $x->[0]" ); 


a: 
b: some text 


Связано это с тем что оператор =~ в list конексе выдаёт список совпадений (и сответственно пустой спискок, если совпадений нет), таким образом первый аргумент просто исчезает, остаётся только второй.

По поводу того что они зло:

У них другое назначение, не как в других языках. Они не предназначены для контроля параметров. Они предназначены для правильного распознавания контекста (scalar vs list) а так
же для вызова подпограмм без скобок.

подробнее здесь.

stackoverflow.com/questions/297034/why-are-perl-5s-function-prototypes-bad
www.perlmonks.org/?node_id=861966

Как говорят в статье правильнее было бы их назвать «parameter context templates»
в Perl (как и во многих других языках) X && Y, в случае если X — false, возвратит не просто false (не выполняя Y), а возвратит сам X

Может быть я что-то не понимаю, но почему в результате булевой операции возвращается небулево значение? Вы не могли бы объяснить, зачем так сделано? Я еще понимаю такое поведение в строготипизируемых языках, но тут то такие фокусы не должны срабатывать.
Да так в любом языке, разве нет?

ruby -e 'puts false && 3'
false


ruby -e 'puts  nil && 3'


ruby -e 'puts  false || "Hello"'
Hello


Часто используемое x = yy || zz на этом основано. Никому ведь не хочется в данном случае в x увидеть true или false. Хочется yy или zz, причём они могут быть скалярами или объектами.
Не во всех, например:
php -r 'var_dump(false || "Hello");' bool(true)
На мой взгляд — это крайне неявное поведение. А неявное поведение — прямая дорога к ошибкам. Чем меньше неявного поведения, тем сложнее ошибиться. Статья то как раз и про это.
а вместо странной булевой операции
x = yy || zz
я бы использовал симантически более правильный и такой же компактный тернарный оператор:
x = (yy?:zz)
Вы какие-то странные вещи говорите. Это крайне явное, документированное поведение.

Не бывает никаких «интуитивных операторов», а про php у меня такие интересные истории есть.
Так там история не про PHP, а про то, что автор не знал, что такое ассоциативность операторов, и уж тем более не знал про то, что она может от языка к языку отличаться. Но про «не бывает интуитивных операторов» вы совершенно правы.
В ruby/perl, если хотите привести результат к явному boolean — можно использовать оператор '!!'. Что в общем то и делают — при передачи логического значения в функцию или возвращении логического значения, приводят его к boolean (кто знает что с ним функция будет делать — может попытается сериализовать или будет утечка памяти итд)
Это не булевые операции. Булевые это: | и & (без удвоения символов)
ну, а в чем разница? булевая арифметика и применяется дли бит
В том и разница, что применяется для индивидуальный битов, а не к значению целиком:
❯ php -r 'var_dump((bool)(2&1), 2&&1);'
bool(false)
bool(true)
Даже в такую чистую вещь как передача аргументов в функцию засунули свои грязные императивные ручки.
Да, они передаются по ссылке. Вроде бы можно сделать
sub a
{
 my ($b,$c) = @_;
}


(как обычно и делается)
и вуаля — аргументы уже переданны не по ссылке а по значению. По крайней мере $b и $c можно изменять, ничего с оригиналом не случиться. Но нет, разница всё же есть…
Я лишь говорю о том, что во время формирования структуры аргументов производить какие-то операции с изменением переменных — дурная идея.

Если человек отлаживал код на Perl'е, то знает что $myvar->[0] может изменить переменную.
Я честно говоря на столько редко сталкивался с autovivification, что просто забыл про неё, если бы мне показали кусок кода где явно дело может быть только в autovivification я бы наверное вспомнил.

Ну тут регэксп выдал истину, в том случае когда искомой строки ну нигде поблизости в коде просто не было…
Это я почему про отладку вспомнил, когда единственным изменениям в исходнике является простой Dumper, который обращается к $myvar->{'blabla'}{'catchme'}, а программа уже начинает работать иначе, то такие особенности языка довольно сильно отпечатываются в памяти.
UFO just landed and posted this here
Я так понимаю всем понятно зачем писать такой код, да?
Тогда объясните мне, пожалуйста, ЗАЧЕМ ПИСАТЬ ТАКОЙ КОД!?
Внизу поста написан реальный пример
should catch exception
Хм, да, виноват.
Невнимательно читал.
Сам использую первую часть кода, но передавать ту же переменную в качестве второго параметра не пробовал.
Отлично! Дополнение в копилку к остальной тысяче способов отстрелить себе ногу в Perl.
(Я почти уверен, кстати, что этот случай описан в PBP)
Корень проблемы в том что, например, ($x && $y) = Z не работает, т.к. ($x && $y) — не lvalue. Однако, при передаче в функцию оно ведёт себя как lvalue. Это даже вроде описано в perl parameter aliasing.

use strict;
use warnings;
sub a
{
    $_[0] = 3;
}
my $x = 0;
my $y = 5;
a($x && $y);
print "$x\n";


печатает 3.
* Это даже вроде НЕ описано в perl parameter aliasing.
Но там (PBP), ЕМНИП, написано «распаковывайте аргументы иначе получите action-at-a-distance».
Вообще-же размер PBP удивляет.
Попытаюсь поискать
Стр. 178, глава «Argument Lists».
Множество этих вещей в PBP описаны.
Ааа, это к моему последнему примеру с
$_[0] = 3;

относится. Это да, понятно, что $_ модифицирует аргументы.
Пример был больше как PoC что ($x && $y) можно модифицировать.
О каком случае идёт речь?

Тут на лицо абсурдное условие было:

ok( ($errors && ($errors->[0] =~ /My Exception/i)), "should catch exception $errors->[0]" );

Первый раз перед тем как написать $errors->[0] мы проверили что есть $errors, а второй раз — нет.
Sign up to leave a comment.

Articles