-
Notifications
You must be signed in to change notification settings - Fork 18k
proposal: Go 2: allow goto to jump across variable declarations #27165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I like this. |
@griesemer Should the title say "allow goto" instead of "allow variables"? |
I Would it be valid to redeclare a variable after a goto? For example,
That is, are the lines between
II Does this interact with garbage collection at all? If i understand things correctly, currently the garbage collector is allowed to reclaim variables as soon as they are no longer used, regardless of whether they are officially "out of scope", so nothing would really change under this proposal. Just checking. |
@magical Thanks for catching the typo in the title. Fixed. No, I think it would be a mistake to introduce what you call "pseudo scopes". That would make this proposal much more complicated. It would also lead to hard to understand code, because one could have what looks like double declarations of variables (per your example) which are in fact different variables even though they appear textually in the same scope. That seems like a bad idea. This proposal is strictly about restricting the It's important to keep in mind that using labels and goto's is not really a recommended coding style. But in some limited situations, using a goto is exactly the right thing. And in those cases it would be nice if we wouldn't have to compromise the quality of the code further by being forced to move variable declarations from the preferred locations to before a Regarding garbage collection: The question is not so much about garbage collection, but about the layout of variables in an activation frame. As long as we make sure that variable locations are properly initialized at all times for garbage collection to work, or the compiler can provide the correct used/unused information at each GC point, I think there shouldn't be a problem here. For all I know there is nothing to do here, but @randall77 or @aclements will be able to give the authoritative answer. |
@griesemer Thanks for the clarification. I agree that it would be overly confusing, so I'm glad that it wouldn't be allowed. |
I like this but you don't have to declare the variable before the
|
I'm not 100% positive, but I believe you're right that this doesn't have any particular interaction with the garbage collector. Variables affected by this proposal must already be dead at the label, so it won't matter whether or not they're initialized in the frame. It's possible this would have some interaction with ambiguously live variables, for example if you jump from a location before an ambiguously live variable is declared to a location where it is ambiguously live. This may require zeroing the ambiguously live slot before the jump. I suspect @randall77's stack tracing change will make this a moot point anyway. |
I've edited the proposal per the discussion in #26058 (comment) . Also, the original proposal text suggested that variables that must not be accessed after a label should be removed from scope to achieve that effect. But that would permit another variable with the same name to be declared in the original scope. That seems like a bad idea. In #27165 (comment) I had explained as much without noticing the difference from the earlier proposal text. I've added a further example to the original proposal text. |
Possible refinement: Instead of disallowing variable access after a label if a |
Wrapping code between the goto and label with a {} block seems to work now and provides some explicit indication of intent regarding scope of declared variables in that range. Putting gotos inside the block to jump out also seems to work now. Just worried about impacts to one of golang's greatest features.. clarity of intent is very explicit. |
Closing in favor of #26058, which is the same idea expressed in a slightly different way. Both issues accept the same set of programs; the difference is whether the error is reported on the use of the variable or on the |
Problem statement
The current rules for the
goto
statement state:In short, a
goto
statement is not allowed to jump across variable declarations (jumping across nested scopes that declare variables is ok). The underlying reason for that rule is that such variable declarations will not be executed when thegoto
is taken and thus the respective variables may be in an undefined state (not initialized, not heap-allocated, etc.) at the target label.This is unfortunate because many times when a
goto
is used at all, we don't actually care about the values of such variables. A perhaps typical example is the use ofgoto
to factor out error handling to the end of a function:Other common scenarios are uses of
goto
's for early exit where there is no error handling but some finishing up code (e.g., look forgoto done
,goto out
,goto skipped
, etc. in the std library).If the code above needs to use a new variable in the code following the
goto
and before theError
label, that variable cannot conveniently be introduced close to where it is used, but instead will need to be declared before thegoto
. Often this also means that one cannot use a short variable declaration because the program state is not what is needs to be for an initialization expression.In summary, using a
goto
sometimes requires that otherwise unaffected code will need to move variable declarations before the use of thegoto
since thegoto
would not be permitted otherwise. This is at best annoying, and at worst may lead to less readable and maintainable code due to bulk variable declarations, without initialization expressions, sometimes much before they are actually needed.Observation
Obviously, if code accesses a variable at a target label of a
goto
, that variable must be declared before thegoto
as otherwise its value may be unknown. But the values of variables that are not accessed at the target label don't matter exactly because the code doesn't use those values.This observation leads directly to the proposal.
Proposal
We propose to remove the
goto
restrictions on variable declarations in favor of a new rule for variable accesses (edited per discussion):Examples
The code fragment:
currently is invalid and leads to the compiler error:
To make it valid, we would need to write something like:
With the proposed new rule, the
goto
error will disappear, making the original code fragment valid. On the other hand, if the code were to make use ofx
at the labelL
as well:the compiler might report instead (edited per discussion):
The error reported currently with the
goto
statement could be used literally as explanation in the error reporting the invalid variable access at the target label.It is important that the variable remains in scope to make it impossible that another variable with the same name is declared in what used to be the variable's scope if there was no goto. For instance, the following code remains invalid with this proposal:
Implementation
The implementation is expected to be straight-forward: The new rule shifts an existing error, reported with a
goto
, to a specific access of the variable which caused thegoto
error. More detailed:Whenever the compiler's analysis detects that a
goto
jumps over a variable declaration, instead of reporting that as an error, the compiler remembers that variable as inaccessible at the target label.At the target label, all such inaccessible variables are removed from scope. This will in turn make it impossible to access such a variable in the code. (A more user-friendly implementation might keep the variable in scope but upon access would also check if it was marked inaccessible. Such an approach could provide a better error message).If the variable is accessed lexically after the target label, the compiler reports an error.Alternatives
#26058 proposes an alternative approach to achieve a similar outcome: Instead of disallowing variable access if a
goto
jumped over the variable's declaration, #26058 disallows agoto
if it jumps over a variable declaration of a variable that is used after the target label. In other words, #26058 makes the existing restriction ongoto
's slightly less onerous while this proposal removes that restriction altogether but introduces a new one for variables.Summary
This proposal removes a restriction on uses of
goto
's in favor of a new rule for variables: Instead of making it invalid for agoto
to jump over a variable declaration, it will become invalid to access a variable (after a label) whose declaration was jumped over. This is an improvement over the existing situation because the current rules always disallow variable declarations that are being jumped over, while the new rules only lead to an error if such variables are used at the target label, which is a less common scenario.Because the proposal removes an existing restriction, this is a backward-compatible language change.
#26058 achieves a similar outcome through a slightly different approach. It does not seem obviously clear which approach is better.
The text was updated successfully, but these errors were encountered: