在单个语句中使用增量和变量后重用,Perl 5与Perl 6

在单个语句中使用增量和变量后重用,Perl 5与Perl 6,perl,undefined-behavior,raku,sequence-points,Perl,Undefined Behavior,Raku,Sequence Points,我天真地认为可以在Perl 6和Perl 5之间相当准确地翻译的一行代码实际上没有翻译,这是因为处理增量后变量的方式不同 这个Perl6产生了期望的结果,一个幻方:[[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;

我天真地认为可以在Perl 6和Perl 5之间相当准确地翻译的一行代码实际上没有翻译,这是因为处理增量后变量的方式不同

这个Perl6产生了期望的结果,一个幻方:[[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;
Perl5中的“相同”代码没有:[[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++;
}
如果递增或递减操作的返回值是该操作之前的变量值,那么Perl 5似乎是错误的。但是对代码的实验表明,
$i%$n
条件的结果是差异的根源,因此似乎Perl 6依赖于
$i
的值的方式并不是严格保证的


因此,我应该对Perl 6起作用而不是Perl 5不起作用感到更加惊讶。

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
计算等式左侧的索引。

如果在一条语句中修改和读取同一变量,Perl 5和Perl 6都不能保证定义的行为

Perl6概要谈到了,但我相信它们也适用于语句中的读写问题


但一般来说,在这两种语言中都不能依赖它。

“递增或递减操作的返回值是操作前变量的值”是的,但等号两边都使用了
$i
的值,因此放入数组的结果可能是操作前的值,但索引操作中
$i
的值可能是操作后的值?另请参见:这是用于混淆的Perl竞赛吗?它来自rosettacode.org,人们都知道它owboat…@HåkonHægland你应该回答这个问题。这里唯一的问题是perl5首先计算标量赋值的右侧,而perl6似乎计算左侧。代码的静态分析是否可以发现由此导致的未定义行为的可能性?(此处“this”是单个语句中变量的多个用途的组合,其中一个用途是显式修改变量或方法调用,因为方法调用可能修改值。)@raiph,显然,它可以捕获某些情况。甚至可能有一个
perlcritic
规则可以做到这一点。但它也不能捕获所有情况。例如,无法知道
$\u0]
$\u1]
是否会在
sub{++$\u0]+-$\u1}中别名为同一个变量
。这就是为什么它是未定义的行为而不是编译时错误。Re“如果您在一条语句中修改和读取同一个变量,Perl 5和Perl 6都不承诺定义的行为”。不完全如此。Perl5实际上或多或少地记录了将在LHS之前评估赋值的RHS。例如,
local$x=f($x);
我的$x=f($x);
是有效的。这是一个灰色区域,因为虽然特定案例被记录为有效,但不清楚这在多大程度上是正确的。但文档中有一个基础,Perl5的所有版本和版本都会在LHS之前单独执行RHS分配。简言之,您可以在这里依赖Perl5的行为。(不过你不应该这样,因为它很难阅读。)