szr said:
$tail = ($tail->[1] = [$_]);
^^^^^^^^^^^^^^^^^^^^^
Is it any surprise that it segfaults when you're using a construct with
undefined behavior?
how is that behaviour undefined?
perldoc perlop:
Note that just as in C, Perl doesn’t define when the variable is
incremented or decremented. You just know it will be done sometime
before or after the value is returned. This also means that modifying a
variable twice in the same statement will lead to undefined behaviour.
AFAIK this is the only place in the perl doc which refers to "undefined
behaviour".
However, this is very unclear. Unlike C, which has a general rule which
defines when modifying an lvalue yields defined behaviour and when it
yields undefined behaviour, Perl doesn't. We don't even know if that
paragraph refers only to the ++ and -- operators or to all assignment
operators. Also in C, "undefined behaviour" really means "anything can
happen, including a crash, the compiler refusing to compile the program,
or a sudden affluence of nasal demons. The above paragraph (as well as
the next sentence "Perl will not guarantee what the result of the above
statements is.") suggest that only the order of evaluation is undefined.
By C rules,
$tail = ($tail->[1] = [$_]);
is undefined, because an lvalue which is modified between to sequence
points may be read only to determine its new value. In the above
statement, $tail is modified ($tail = ...) and also read ($tail->[1]),
but not to determine its new value, but to determine the location to
which [$_] will be assigned. (Although that's a bit of an edge case - I
think one could argue that $tail is needed to compute $tail->[1] in turn
is needed to determine the value of ($tail->[1] = [$_]) which is then
assigned to $tail. But then, because of autovivification, assigning to
$tail->[1] may modify $tail, so $tail would be modified twice between
two sequence points, which is also forbidden, so this would again be
undefined).
But I don't think C rules apply to Perl. The languages are too
different, and the Perl docs should be fixed to spell out the rules for
Perl.
Basically I see three possibilities:
1) Eliminate "undefined behaviour" completely: Work out how expressions
are evaluated by current perl, document it and specify it as the way
it should be.
2) Specify some rules for expression evaluation, but leave some details
explicitely unspecified. For example, one could specify that any
subexpression of an operator is completely evaluated before the
operator, not specify the order in which the subexpressions are
evaluated.
3) Stick with C's idea of sequence points and document where they occur
and what counts as "modifying an lvalue".
Personally, I'm in favour of 2, but right now I couldn't come up with a
consistent set of rules which explains why
perl -e '$i = 5; $x = ++ $i + $i ++; print "$x\n" '
prints 13.
hp