Re: How does 'goto LABEL' search for its label?
by Athanasius (Archbishop) on Jan 16, 2013 at 13:59 UTC
|
From the Camel Book, 4th Edition, page 149:
The goto LABEL form finds the statement labeled with LABEL and resumes execution there. It can’t be used to jump into any construct that requires initialization, such as a subroutine or a foreach loop. It also can’t be used to jump into a construct that has been optimized away.... It can be used to go almost anywhere else within the current block or any block in your dynamic scope (that is, a block you were called from). You can even goto out of subroutines, but it’s usually bettter to use some other construct.
Update: See also the similar discussion on page 881, and note (for whatever it’s worth) the following rather cryptic comment in the section “Time Efficiency” on page 692:
- Avoid goto. It scans outward from your current location for the indicated label.
Hope that helps,
| [reply] [d/l] [select] |
Re: How does 'goto LABEL' search for its label?
by toolic (Bishop) on Jan 16, 2013 at 14:03 UTC
|
Who can help?
I certainly can't, but maybe B::Deparse sheds some light.
| [reply] |
Re: How does 'goto LABEL' search for its label?
by LanX (Saint) on Jan 16, 2013 at 16:26 UTC
|
Do you have a clear definition for "construct"?
from perlglossary
construct
As a noun, a piece of syntax made up of smaller pieces.
I think in this context it's supposed to mean "block of a loop".
IMHO this discussion helps: cross scope gotos?
From what I remember labels are only visible from the actual "frame" and parent frames.
Frames are constructs which need an initialization like subs or for-each-loops (remember the aliased loop-var!).
That means you can't jump into these constructs and bypass initialization.
But if you call another sub from within such a frame, that means after run-time initialization, you can goto back.
So lables are a run-time thing. They belong to the dynamic scope like localized vars.
EDIT: I think the deprecation is supposed to disallow jumps into other kinds of loops like while¹ or c-style fors , which have a "logical" but no "physical" initialization like frames.
HTH!
¹) remember that naked blocks are internally just while-loops | [reply] [d/l] [select] |
|
I think in this context it's supposed to mean "block of a loop".
goto says that literally
IMHO this discussion helps...
The whole time I was writing Re: How does 'goto LABEL' search for its label? I was thinking "dynamic scoping" but didn't have an example, and here it is
$ perl -wE " sub F { G(); LF: say 6; } sub G { say 2; goto LF; } G; "
2
Can't find label LF at -e line 1.
$ perl -wE " sub F { return G(); LF: say 6; } sub G { say 2; goto LF;
+} F"
2
6
yow :) | [reply] [d/l] |
|
I sympathized with the "yow" remark because it looked like the difference between finding the label and not finding the label was whether "return" was used. But that was a red herring.
The real difference is whether the one-liner ends with "G" or with "F". The inclusion of the 'return' keyword makes no difference (but lacking the 'return' when calling "F" makes the reason for the output less obvious).
Once I noticed the single-character difference off at the end of the long lines, then I lost sympathy for a "yow" response because the behavior is exactly as I would have expected from the documentation. And, it seems a reasonable restriction.
Now, I think using 'goto' to leave a subroutine is a rather squirrely technique. I would much prefer that it produced a warning so you'd have to write such squirrely code more like:
sub F {
return G();
LF: say 6;
}
sub G {
say 2;
no warnings 'exiting';
goto LF;
}
G();
Indeed, I'm not sure why the -w you used fails to trigger this:
=item Exiting subroutine via %s
(W exiting) You are exiting a subroutine by unconventional
means, such as a goto, or a loop control statement.
| [reply] [d/l] [select] |
|
|
|
|
|
> > I think in this context it's supposed to mean "block of a loop".
> goto says that literally
Really? Where?
And I hate the fact that it uses the term "construct" in two different meanings!!!
I'd really love to have the $cash to hire a crowd of math students to look thru the perldocs to clean up the wording.
| [reply] |
|
|
|
Re: How does 'goto LABEL' search for its label?
by Anonymous Monk on Jan 16, 2013 at 15:32 UTC
|
goto says (among other things) Use of "goto-LABEL" or "goto-EXPR" to jump into a construct is
deprecated and will issue a warning. Even then, it may not be
used to go into any construct that requires initialization, such
as a subroutine or a "foreach" loop. It also can't be used to go
into a construct that is optimized away.
So LABELs are like lexicals, except with only file-scope or subroutine-scope ( Lexical scoping like a fox )
lexical(my) variables from one loop/block is not visible in another, but labels are , because they currently have file scope (like my $foo at the top of a file outside of any bare blocks)
currently { L: say 1; } is like my $L; { $L=1; say $L; }
But this will change, once Use of "goto" to jump into a construct is deprecated is disallowed, labels will be lexically scoped like my $vars
someday { L: say 1; } is like { my $L=1; say $L; }
| [reply] [d/l] |
|
| [reply] |
Re: How does 'goto LABEL' search for its label? (call stack)
by tye (Sage) on Jan 17, 2013 at 03:53 UTC
|
I believe it is a rather simple search up the call stack. And all of your examples agree with that. Don't confuse that with searching up a "stack" of nested (or even prior) lexical blocks.
A 'goto' is visible inside of the bounds of the dynamic scope where it lives. The two things that most clearly define a dynamic scope are: sub, eval. This certainly includes the subs that you can define without using the 'sub' keyword by passing a block to a sub with a prototype that starts with a '&' character. It is less clear how similar the separation is for similar scopes that can be built in a lot of places in Perl, including: map, grep, s///e, sort.
So apparently, the construct containing the label has to have been executed once.
Not true. The construct just mustn't be optimized away as happens when you give an 'if' statement an expression that is known to be false at compile time.
$ perl -wE 'sub g() { label: say "here" }; g; goto label'
here
Can't find label label at -e line 1.
Of course. g() has already returned by the time you execute "goto label", so the contents of g()'s dynamic scope are not present further up the call stack, so Perl can't find the "label:".
As for there being a new warning for "if(1){X:...} goto X:", I lack the details for why this got deprecated. It seems to go rather farther than any prior restrictions and seems likely to run afoul of rather typical "use of 'goto' for error handling" that I've seen (though not frequently):
...
if( ... ) {
goto ERR;
}
...
if( $fatal ) {
ERR:
... clean up after fatal error ...
}
| [reply] [d/l] [select] |
|
Thanks tye, your reply did clear up a few things.
I had two problems with my mental model. I didn't remember that that if (0) { } gets optimized away. I also wrongly assumed that each block produces a stack frame.
As for there being a new warning for "if(1){X:...} goto X:", I lack the details for why this got deprecated.
I didn't find many details either, just that without it, the implementation of lexpads would be much simpler and saner.
Now I must go back and study the crufty error handling code I inherited, and see if it can be rescued (or if I can safely argue that it must be rewritten to use something saner).
| [reply] [d/l] |
|
just that without it, the implementation of lexpads would be much simpler and saner.
Yeah, that would have been my best guess. I'm curious about how "much" simplification we are talking about. But I'll go digging in the p5p archives for more details if I find the time and motivation. :)
I wonder if the complications could be avoided by having behavior closer to this pseudo-Perl code:
if( $fatal )
ERR: {
...
}
So that the destination for "goto ERR;" would be the start of the lexical block instead of the first line in the lexical block.
It would be nice if a label pointing to the first line of a lexical block could just be moved to point to the start of the lexical block, avoiding the complexity and the need for deprecation. That is:
if( $fatal ) {
OK:
... no need to deprecate this ...
}
if( $fatal ) {
my $foo;
BAD:
... "goto BAD" from outside this block deprecated ...
}
But, if one ends up using a Perl that has the deprecation but doesn't implement my idea, then it should often be relatively easy to rewrite the code to be more like:
...
if( $whatever ) {
goto ERR;
}
...
if( $fatal ) {
# Used to be "ERR:" here
goto ERR;
}
return ...;
ERR:
... code moved from if( $fatal ) ...
| [reply] [d/l] [select] |
|
> perl -MO=Deparse -E'if (1) { label: say 1;}; goto label'
BEGIN {
$^H{'feature_say'} = q(1);
$^H{'feature_state'} = q(1);
$^H{'feature_switch'} = q(1);
}
do {
label: say 1
};
goto label;
... which seems to fall into the same category like other loop-like-blocks:
ATM I have only 5.10 available. Could someone please test this with >= 5.12?
perl -wE'do { label: say 1;}; goto label'
EDIT: removed exit
Update
here test code w/o endless looping.
perl -wE'my $x=0;do { label: say $x++; die if $x>1}; goto label'
0
1
Died at -e line 1.
Update
Thanks to davido for testing
[davido]: LanX: perl -E 'goto IN; do{ IN: say "Hello world\n";};' does
+ produce the warning on 5.16.2.
¹) which is somehow strange, I expected a simple bare block. | [reply] [d/l] [select] |
Re: How does 'goto LABEL' search for its label?
by sundialsvc4 (Abbot) on Jan 16, 2013 at 16:12 UTC
|
And I, for one, still will go on-record as having rejected in code review every piece of logic I have ever encountered (other than in profoundly specialized cases such as device-drivers and parsers) that contained a goto. And here’s the very-simple reason why:
The program’s internal state, at the point of the label, is solely determined by the internal state at every point that “goes to” that label ... not (only) by the statements which surround it or precede it. You can, intentionally or worse-yet unintentionally, introduce an error of the most-undebuggable kind at any point in the future ... and if what you did is syntactically acceptable, the compiler won’t say a word of warning to the effect that you just planted a high explosive device with a hair-trigger underneath your foot.
This causes the software complexity meter to spike “infinity,” and for no purpose that cannot be better-achieved in some other way. Even the “toy” example in the OP is effectively impossible to understand ... even as-written, and only if some other goto is not later added, somewhere, anywhere, anytime. (Yes, I am intentionally stretching syntactic truth slightly to make a point ...) You have to think to realize that what this logic is actually doing is if ($arg != 1).
The Perl language evolved a number of constructs, such as last LABELNAME, specifically to accommodate the control-constructs that do indeed occur from time to time in production programs, and to handle them in a way that still affords for efficient code-generation and pragmatic goof-detection. But goto, except in the edge-cases I previously mentioned, is an unnecessary bad-idea that should never be accepted in production code. (The edge-case exceptions are not frequent-enough to justify softening the word, “never.”)
| |