-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
proposal: Go 2: add trap on direct assignment with select block #66161
Comments
Similar, except for introduction of new keyword |
Well the main difference is that this doesn't call a function but injects a switch block in predictable locations. Also this is intended to be purely at compile time only. |
What about assignments through pointers, and additionally in other functions?
|
See also #56258. |
Assignments in other functions would not have the trap appended. Assignments through a pointer would but only if the variable named in the trap is a pointer. The trap block is injected only if there is a = or := statement. So @randall77 in your examples no trap block is injected unless if there also is a select block for p. The assignments are though the p variable not through the err variable. Like this this proposal remains a pure compile time text expansion that is easy to understand. The difference with the other proposal is that the trap is installed explicitly and statically on a named variable, not on the _ variable. |
So
? |
That does trap because err is mentioned explicitly. That is the point of this proposal, everything is explicit! :) Of course doing *(&err) is a bit obtuse. Edit: |
For extra fun , add arbitrary other complications between the two statements, like
The general point is that at any pointer assignment, how do you tell whether it is assigning to a trapped variable or not? |
Then it is "assignments through pointers don't trap". The idea is that the trap is strictly compile time and nominal only, which makes it a lot simpler to implement than, say, a defer statement for which Go has to keep a runtime list. As I see it it will still be very useful even with these restrictions. Edit: this is also how it this proposal is different from simply using a defer() statement for error handling as we can already do with the help of generics e.g. this comment: #57645 (comment) |
Is the panic here "trapped" or "untrapped"? var err error
f := func() { err = io.EOF }
select err {
case err != nil:
panic("trapped")
}
g := func() { err = io.EOF; panic("untrapped") }
f()
g() Is the panic here 1 or 2? What gets printed before the panic? var err error
select err {
case err != nil:
println(1)
panic(1)
}
select err {
case err != nil:
println(2)
panic(2)
}
err = io.EOF |
The anonymous func is a separate scope so untrapped. The second trap block overwrites the first one so for the second example it is 2 only. |
Based on the discussion above, and the similarity to earlier declined issues, and the emoji votings, this is a likely decline. Leaving open for four weeks for further comments. |
Thanks for considering this. While this proposal does not seem to be what we need, maybe it will help finding a better idea for error handling by elimination. |
No change in consensus. |
Go Programming Experience
Experienced
Other Languages Experience
C, Ruby, Pascal, Basic, Java, Shell, ...
Related Idea
Has this idea, or one like it, been proposed before?
Not that I know of. It is somewhat inspired by the trap statement in certain shells.
Does this affect error handling?
Yes, although it is a language feature of general use. It differs because it is explicit, and can be used not only for error handling, but also for reducing boiler plate.
Is this about generics?
No.
Proposal
The select block is extended to allow a single variable after select and before the block. This installs a trap on the variable that is triggered when any value is assigned to the variable. In the body of such a select block case statements can be used to check the value of the variable. The contents of the select block are executed as if a switch statement with the body of the select statement had been injected just after the statement that caused the variable to be assigned to.
The trap remains in effect for as long as the variable is in scope. The select trap must be defined at the same block level as the variable, so, unlike a defer statement, it is not allowed to do so conditionally in an if or switch block. The trap is not appended for indirect assignments through a function or pointer. the trap is only injected for direct assignments or for assignments to members. For example
err=
, or in case of a structerr.Foo=
. This makes the question if a variable has a trap or not decidable at compile time.Example:
Language Spec Changes
No response
Informal Change
No response
Is this change backward compatible?
Yes. In stead of
select
, a new keyword liketrap
could also be introduced, but usingselect
is strictly backwards compatible.Orthogonality: How does this change interact or overlap with existing features?
This is an orthogonal new feature that can be used not only for error handling, but also to reduce repetitive boilerplate in other cases.
Would this change make Go easier or harder to learn, and why?
Somewhat harder as it is a new feature, but it would also simplify error handling and help reduce boilerplate.
Cost Description
No response
Changes to Go ToolChain
All of them.
Performance Costs
Compile time: extra injection work on trapped variables. Run time cost: none.
Prototype
The compiler would simply inject the code block substituting select for switch. That should be quite easy to implement.
The text was updated successfully, but these errors were encountered: