1. Swaps the order: First "return" is explained, then
the rest (as a way to encourage the use of "return".)
2. The second explanation is reworded in terms of statements.
I tried hard to come with something brief. In my opinion it has no
sense to devote several lines to this topic in order to be exact. The
way I wrote it, however, implies that the common
if ($something) {
$this;
} else {
$that;
}
is documented as returning an unspecified value. I don't know whether
this is a good idea in the sense that people already use that idiom.
The return value of the equivalent expression using the ternary
operator is specified though.
-- fxn
> This is a documentation patch that tries to fix the issue we
> discussed today regarding perlsub, it does two things:
And it didn't do a third thing, to pass the spell checker :-).
-- fxn
Thanks, applied as change #25812.
I dont think it should have been. It has massive backwards compatibility issues.
With a stroke of a pen (in a maneer of speaking) you have just
rendered thousands and thousands of lines of code undefined.
This is really bad. A change like this should not occur without Larry
approving it.
Cheers,
yves
--
perl -Mre=debug -e "/just|another|perl|hacker/"
Why? I didn't changed any code, and don't plan to.
I believe he said why:
> > With a stroke of a pen (in a maneer of speaking) you have just
> > rendered thousands and thousands of lines of code undefined.
Based on this documentation change, the result of any code that does this:
sub foo {
if (@_) {
return 0;
} else {
return 1;
}
}
is now undefined.
Would it be sufficient if the documentation referred specifically to loop
control structures, rather than control structures in general?
Ronald
Because the patch as stated in the original submission implies that
the return of
sub { if (shift) { 1 } else { 0 } }
is undefined. This means that by applying you just changed the
expected behaviour of hundreds and hundreds of routines out there from
something intuitive and meaningful to something undefined. I havent
bothered to do a count but this would impact a good chunk of the
internals code.
In fact you might as well have just said "implicit returns are now
prohibited." The wording you applied is:
+If no C<return> is found and the last statement is an expression, its
+value is returned. Otherwise, for instance if the last statement is a
+control structure like a C<foreach>, the returned value is unspeficied.
+The empty sub returns the empty list.
Since the last statement in the subroutine is a control structure the
behaviour is undefined.
Furthermore this is a bit drastic, the behaviour of sub { 1 for 1 } is
broken, not the rest of the control structures, but we have suddenly
said that the presence of control structures blows away implicit
returns.
Unless Larry wieghs in and says that this is a reasonable
intrepretation (at which point ill eat my hat) id say that this
grossly changes the expected behaviour of a huge porportion of the
Perl code that has been written.
The original documentation was a very clever mechanism for handling
implicit returns. We should fix the bug in foreach (that it leaks
internal flags into the perl side of the code) and not change the
expected behaviour of zillions of lines of code.
Yves
Precisely.
>
> Would it be sufficient if the documentation referred specifically to loop
> control structures, rather than control structures in general?
Why dont we just accept that the current behaviour of foreach is broken?
perl -e "my @b=(0,1); print $b[0+ do { 1 for 1}]"
segfaults (on my perl 5.8.6 anyway)!! This behaviour is broken broken
broken. All this talk of statements has dazzled people into thinking
something that is irrelevent is relevent. It shouldnt matter what the
last statement was executed, it should only matter what the last
expression that was evaluated resulted in, not the statement context
that allowed an EXPR to be evaluated.
The behaviour of the other control structures works exactly as would
be expected from the original documentation. Afaik the only problem
is foreach(). Thus we should fix foreach or special case its
documentation in this respect.
Yves
> On 10/21/05, Rafael Garcia-Suarez <rgarci...@mandriva.com> wrote:
>
>> Xavier Noria wrote:
>>
>>> On Oct 20, 2005, at 22:43, Xavier Noria wrote:
>>>
>>>
>>>> This is a documentation patch that tries to fix the issue we
>>>> discussed today regarding perlsub, it does two things:
>>>>
>>>
>>> And it didn't do a third thing, to pass the spell checker :-).
>>>
>>
>> Thanks, applied as change #25812.
>>
>
> I dont think it should have been. It has massive backwards
> compatibility issues.
This goes without saying in a mailing list like this one, but let me
stress that my patch was just a proposal, certainly the one I liked
the most, but it was open for discussion.
> With a stroke of a pen (in a maneer of speaking) you have just
> rendered thousands and thousands of lines of code undefined.
Those lines in general were relying on something ill-specified, they
were already broken from the start. See for instance another example:
% perl -wle 'sub foo { until (1) { 1 } } print 2 if foo() == 1'
Use of uninitialized value in numeric eq (==) at -e line 1.
There are two expressions there, "1" and "1". But we get neither of
them. So to specify these returned values in the docs we need to
start studying case considering all corner cases. As I said a
balanced solution in that direction looks difficult to achieve.
In my view, that old code is already relying on unspecified
behaviour, only it was not yet documented.
-- fxn
Yes, and I expected it to be rejected becuase of the if(){}else{} issue.
I even wrote a reply to your original submission saying this, but got
distracted with Real Life and didnt remember it until i say Raphaels
message saying it was applied.
>
> > With a stroke of a pen (in a maneer of speaking) you have just
> > rendered thousands and thousands of lines of code undefined.
>
> Those lines in general were relying on something ill-specified, they
> were already broken from the start. See for instance another example:
>
> % perl -wle 'sub foo { until (1) { 1 } } print 2 if foo() == 1'
> Use of uninitialized value in numeric eq (==) at -e line 1.
>
> There are two expressions there, "1" and "1". But we get neither of
> them. So to specify these returned values in the docs we need to
> start studying case considering all corner cases. As I said a
> balanced solution in that direction looks difficult to achieve.
>
> In my view, that old code is already relying on unspecified
> behaviour, only it was not yet documented.
Yes, id agree that the last expression evaluated here was a true value.
Ok, so its not just foreach(). I apologise for that generalization in
my other post.
OTOH, this is pretty well the result I would expect after a while() or
for(;;) loop.
OK, so what about the following patch ?
It document what exists. We can try to fix some of the existing cases
and change the documentation accordingly.
==== //depot/perl/pod/perlsub.pod#60 - /home/rafael/p4blead/pod/perlsub.pod ====
--- /home/rafael/tmp/tmp.23943.0 2005-10-21 16:40:03.000000000 +0200
+++ /home/rafael/p4blead/pod/perlsub.pod 2005-10-21 16:40:00.000000000 +0200
@@ -83,9 +83,9 @@ aggregates (arrays and hashes), these wi
one large indistinguishable list.
If no C<return> is found and if the last statement is an expression, its
-value is returned. Otherwise, if the last statement is a control structure
-like a C<foreach>, the returned value is unspecified. The empty sub
-returns the empty list.
+value is returned. If the last statement is a loop control structure
+like a C<foreach> or a C<while>, the returned value is unspecified. The
+empty sub returns the empty list.
X<subroutine, return value> X<return value> X<return>
Perl does not have named formal parameters. In practice all you
> OK, so what about the following patch ?
> It document what exists. We can try to fix some of the existing cases
> and change the documentation accordingly.
>
> ==== //depot/perl/pod/perlsub.pod#60 - /home/rafael/p4blead/pod/
> perlsub.pod ====
> --- /home/rafael/tmp/tmp.23943.0 2005-10-21
> 16:40:03.000000000 +0200
> +++ /home/rafael/p4blead/pod/perlsub.pod 2005-10-21
> 16:40:00.000000000 +0200
> @@ -83,9 +83,9 @@ aggregates (arrays and hashes), these wi
> one large indistinguishable list.
>
> If no C<return> is found and if the last statement is an
> expression, its
> -value is returned. Otherwise, if the last statement is a control
> structure
> -like a C<foreach>, the returned value is unspecified. The empty sub
> -returns the empty list.
> +value is returned. If the last statement is a loop control structure
> +like a C<foreach> or a C<while>, the returned value is
> unspecified. The
Yet not enough:
% perl -wle 'sub foo { unless (1) { 1 } } print 2 if foo() == 0'
2
No "1" is returned.
-- fxn
Actually, i wouldnt expect 1 to be returned here. unless(EXPR) is
afaik defined as formally equivelent to
if (!(EXPR)) { }
Thus i would expect it to be reasonable that the last expression
evaluated was !1 whose return value should be false.
By formally defining these constructs as equivelent to other easier to
understand constructs we avoid the issue of the undefined response.
Cheers,
This is much better. It avoids the extreme intrepretations that worried me most.
Personally i think it should be feasable to make it clear which EXPR
is returned after any control structure. For instance i would expect
the return from for(;;) and while() to always be false (which false is
not so clear), as the last EXPR evaluated will always be the condition
whether to execute the loop body.
Foreach is problematic because it isnt defined as equivelent to
for(;;) and thus there should be no EXPR evaluated after the list has
been processed.
until() { } should return some value of true.
while(){} should return some value of false.
for (@LIST) { EXPR } should return the value of the last EXPR
evaluated in the loop body.
Cheers,
> Personally i think it should be feasable to make it clear which EXPR
> is returned after any control structure.
I don't agree here. We shouldn't document this because there is no
such a thing as an expression being returned after a control
structure. This again mixes control structures and expressions.
If we do that we need to say in which parts of the code that
"returned value after a statement" can be used. Again something
weird, consequence of that mixing.
We already have a word for things from which a value has to be
expected, expressions.
The mixing comes from the fact that something private, something that
is the business of the interpreter and has no parallelism with the
grammar has percolated up to the docs somehow. The result is, no
surprise, something that makes sense in the surface, but that it is
ill-specified if you skim a bit.
I think we have to fix that root misunderstanding and everything goes
to its place.
I understand your worries about code already written though, though I
think that code was already broken.
-- fxn
I agree. You can't write
my $x = while (...) { ... }
> If we do that we need to say in which parts of the code that
> "returned value after a statement" can be used. Again something
> weird, consequence of that mixing.
>
> We already have a word for things from which a value has to be
> expected, expressions.
>
> The mixing comes from the fact that something private, something that
> is the business of the interpreter and has no parallelism with the
> grammar has percolated up to the docs somehow. The result is, no
> surprise, something that makes sense in the surface, but that it is
> ill-specified if you skim a bit.
>
> I think we have to fix that root misunderstanding and everything goes
> to its place.
>
> I understand your worries about code already written though, though I
> think that code was already broken.
Those expressions (the ones in loops) are evaluated in void
context, while a return value will typically be evaluated in scalar or
in list context, depending on how the function is called.
$ perl -wle 'sub x {my $x=1; while($x--){$x}}'
Useless use of private variable in void context at -e line 1.
As if() statements are actually compiled as expressions, the warning
about the return value being unspecified doesn't apply.
No. But you can write:
my $x= do { while (...) { ... } };
whose return should be well defined.
> > If we do that we need to say in which parts of the code that
> > "returned value after a statement" can be used. Again something
> > weird, consequence of that mixing.
No, I disagree. Im not saying that the control structer has a return
value, im talking about what is returned if you wrap a sub {} or do{}
around the control structure.
The point is that any control structure is made of multiple elements,
some of which are expressions. The item that should be returned is the
last expression evaluated.
Determining which expression this is for all control structures should
be fairly straightforward, if possibly a touch controversial.
> >
> > We already have a word for things from which a value has to be
> > expected, expressions.
> >
> > The mixing comes from the fact that something private, something that
> > is the business of the interpreter and has no parallelism with the
> > grammar has percolated up to the docs somehow. The result is, no
> > surprise, something that makes sense in the surface, but that it is
> > ill-specified if you skim a bit.
> >
> > I think we have to fix that root misunderstanding and everything goes
> > to its place.
> >
> > I understand your worries about code already written though, though I
> > think that code was already broken.
>
> Those expressions (the ones in loops) are evaluated in void
> context, while a return value will typically be evaluated in scalar or
> in list context, depending on how the function is called.
>
> $ perl -wle 'sub x {my $x=1; while($x--){$x}}'
> Useless use of private variable in void context at -e line 1.
>
> As if() statements are actually compiled as expressions, the warning
> about the return value being unspecified doesn't apply.
>
Any time that you start resorting to internals specific discussion in
an attempt to explain the documentation of perl which is of a much
higher level of abstraction you run into problems.
The point is that the language is defined at a high level, with many
abstractions involved. If the internals happen to reorganize control
structures like if() into EXPR thats the internals problem and it
should make a bit of difference at the perl level.
The problem here as Ive said before is that internals flags are
leaking into the perl world. This is something that shouldnt happen
and when it does we should fix it in such as way as to maintain the
abstraction at the perl layer, and not facilitate whichever
implementation we currently happen to use.
Yves
Why ? This code is useless anyway. Why should one care about what ends
in $x ? Of course we can change it but I fail to see what kind of
value would be useful. It doesn't matter.
> The point is that any control structure is made of multiple elements,
> some of which are expressions. The item that should be returned is the
> last expression evaluated.
No, it shouldn't. In a loop block, expressions are evaluated in void
context. You want to change them to scalar or list context, and this is
likely to break lots of code.
Could we be more explicite than "like"?
print sub {{1}} -> ()
prints '1', as I expect it to do. And a bare-block is a loop control
structure as well.
Abigail
>>> If no C<return> is found and if the last statement is an
>>> expression, its
>>> -value is returned. Otherwise, if the last statement is a control
>>> structure
>>> -like a C<foreach>, the returned value is unspecified. The empty sub
>>> -returns the empty list.
>>> +value is returned. If the last statement is a loop control
>>> structure
>>> +like a C<foreach> or a C<while>, the returned value is
>>> unspecified. The
>>>
>>
>> Yet not enough:
>>
>> % perl -wle 'sub foo { unless (1) { 1 } } print 2 if foo() == 0'
>> 2
>>
>> No "1" is returned.
>>
>
> Actually, i wouldnt expect 1 to be returned here. unless(EXPR) is
> afaik defined as formally equivelent to
>
> if (!(EXPR)) { }
In perlsyn all I can find are logical equivalences. Otherwise, to
find the expressions in a listing you'd need first to check the code
rewriting rules, emulate them somehow, and look for expressions in
the generated code. That sounds quite unsual.
But perlsyn says things like:
The "if" statement is straightforward. Because BLOCKs are always
bounded by curly brackets, there is never any ambiguity about which
"if" an "else" goes with. If you use "unless" in place of "if",
the
sense of the test is reversed.
That does not state a formal rewrite of the code in my
interpretation, therefore the expressions in the body of
sub foo { unless (1) { 1 } }
are two: the 1s. Hence, the restriction to loop control structures is
not enough in my opinion, it leaves at least that hole.
-- fxn