Постинкрементное и переменное повторное использование в одном выражении, Perl 5 против Perl 6 - PullRequest
9 голосов
/ 05 мая 2019

Строка кода, которую я наивно думал, будет переводить буквально между Perl 6 и Perl 5, на самом деле это не так, из-за различий в способе обработки переменной после приращения.

Этот Perl 6 даетжелаемый результат, магический квадрат: [[8, 1, 6], [3, 5, 7], [4, 9, 2]]

my @sq; my $n = 3; my $i = 1; my $x = $n/2; my $y = 0;
@sq[($i%$n ?? $y-- !! $y++) % $n][($i%$n ?? $x++ !! $x) % $n] = $i++ for 0..$n**2 - 1;
say join ' ', $_ for @sq;

«Тот же» код в Perl 5не: [[8, 1, 3], [9, 5, 7], [4, 6, 2]]

$n = 3; $i = 1; $x = $n/2; $y = 0;
$sq[($i%$n ? $y-- : $y++) % $n][($i%$n ? $x++ : $x) % $n] = $i++ for 0..$n**2 - 1;
say join ' ', @$_ for @sq;

Оба работают правильно, если оператор разделен, и всеинкременты и декременты выполняются после присваивания, например, в Perl 5:

for (0 .. $n**2 - 1) {
    $sq[ $y%$n ][ $x%$n ] = $i;
    $i%$n ? $y-- : $y++;
    $x++ if $i%$n;
    $i++;
}

Если возвращаемое значение операции инкремента или декремента равно значению переменной до операции, то Perl5 будет неправильно.Но эксперименты с кодом показали, что результатом условий $i%$n был источник различия, поэтому, по-видимому, Perl 6 может полагаться на значение $i способом, который строго не гарантирован.

Таким образом, я должен был быть более удивлен, что Perl 6 работал, чем тот, который не Perl 5 не сделал?

Ответы [ 2 ]

9 голосов
/ 06 мая 2019

И Perl 5, и Perl 6 не обещают определенного поведения, если вы изменяете и читаете одну и ту же переменную в одном выражении.

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

Но в целом вы просто не можете полагаться на это ни на одном языке.

0 голосов
/ 05 мая 2019

Кажется, что разница между кодами Perl 5 и Perl 6 заключается в том, что код Perl 5 использует обновленный $i раньше, чем Perl 6. Например, следующий код Perl 5:

my $n = 3;
my $i = 2;
my $x = 5/2;
my $y = -1;
my @sq;
$sq[ ($i % $n ? $y-- : $y++) % $n] [ ($i % $n ? $x++ : $x) % $n ] = $i++;
say "x = $x, y = $y";

печать:

x = 2.5, y = 0

тогда как тот же код Perl 6:

my $n = 3;
my $i = 2;
my $x = 5/2;
my $y = -1;
my @a;
@sq[ ($i % $n ?? $y-- !! $y++) % $n][ ($i % $n ?? $x++ !! $x) % $n ] = $i++;
say "x = $x, y = $y";

печать

x = 3.5, y = -2

, поэтому код Perl 5 использует обновленное значение $i++ с правой стороны (то есть $i = 3 для вычисления $i % $n с левой стороны, тогда как Perl 6 использует старое значение $i = 2 для вычисления индексы в левой части уравнения.

...