-
Notifications
You must be signed in to change notification settings - Fork 18k
proposal: Go2: add common way to handle operations safely #22796
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
If I see a fault that occurs in the deep checking example by what means do i go about determining what generated it short of rewriting the expression in the standard format? |
@as sorry, I'm not a good reader. What is |
The syntax for allocation primitives
|
Shouldn't |
@dmkra Go allocates new object as a result of escape analysis.
@adamdecaf I think |
Most of these look like papering over bugs somewhere up the stack, making them quite different from type assertions and map access. |
@hirochachacha
In the expression above, I almost always want to know why it's
If it's !ok, how do I find the reason why it's !ok? |
@hirochachacha |
So this means we get a choice of which expression to write. The shorter version removes error context in favor of a shorter expression. I would rather see the landmines this expression hides rather than allowing users the option to hide them. |
Perhaps sending to a channel should also have a safe equivalent, in case the channel is closed:
That would complement the receive case which already has a second component. |
There has been prior discussion on this--specifically that it makes it easier to design a program where the producer/consumer lines are blurred to the point of the program is completely incorrect. On the other hand, there is one fork maintained by lsub that modifies the language to achieve that behavior. To my knowledge, there has never been a direct discussion of its merits. |
I admit that this proposal can includes #21985.
I also admit I don't have counterarguments against the statement. Hmm. |
@as As for blurring the lines between a consumer and producer, I have to admit that I'm not seeing it. How would having a safe send option allow consumers to even closely resemble producers? On the other hand, a typical parallel producer pipeline can be simplified by only having the channel they are sending on, as opposed to having an extra channel that the producers themselves are consumers of. |
Closing a channel is a signal to the consumer that no more data will be sent through that channel. With that in mind, allowing producers to catch this signal through failed sends to an already closed channel blurs the consumer/producer relationship because that signal is intended to be sent exclusively downstream to the consumers. |
That's currently true, though I'm left to wonder whether this behavior was created out of necessity. Real life doesn't work that way. If you want to ship a package and no one told you the post office is closed today, you don't just throw your package furiously at its closed doors. Yet this is how channels currently work. Not very intuitive for people trying to pick up the language. |
Actually before Go 1.0 the idiom was if !closed(c) {
v = <-c
} but this was changed to the current comma-ok rule because a goroutine switch between the call to And I'm not sure about this post office analogy, because the idea of a channel is that you own the post office and can thus decide the hours of operation. How you would model other people trying to give you packages to send to other people I don't know right now. |
What exactly is
Don't we already have that because we can compare interfaces? Why does the result of the comparison need to be a variable and a boolean? |
@nhooyr interface comparison panic if underlying type is uncomparable. https://golang.org/ref/spec#Comparison_operators says:
For example, https://play.golang.org/p/M3KLDx8OUkE |
Huh, TIL. Thanks! |
@andlabs IIUC, post office analogy implies actor model or something. |
I don't think real life works this way either, nobody tells you its closed unless you ask first. If it's open, you give it your mail. A channel is similar to a full-duplex pipe for typed values, and the correct way to orchestrate work through it is similar to a UNIX pipeline.
To drive to the post office first and only find out it's not open is lack of organization and planning. You just wasted all that time preparing the packages and driving down there only to find out it's closed. You should know whether the channel is closed before you send on it. Lsub go disagrees specifically with the premise (see link provided earlier), and it seems to be a matter of taste as well as simplicity. The disadvantage with lsub go is that it is a system built for experts who understand the tradeoffs a lot better than the average user. |
For all of the expressions listed, other than interface comparison, the programmer can write an explicit test to avoid the panic. This is not true for the cited examples of map indexes and type assertions. The explicit tests will produce code that is as good as what the compiler will generate anyhow. The new forms can not be used as expressions. It is rare for a slice expression to use an index that might be invalid. Generally you already know that the index is valid anyhow. In the cases where you don't know, the index check condition is often combined with other conditions anyhow, which can not be done using this new form. For instance, Declined. |
@ianlancetaylor |
Guard the channel with another--an inverted semaphore representing the capability to cleanup resources one time works well and replaces sync.Once.
|
I'm probably missing something but it seems to me that you can just use a select statement. sent := false
select {
case c <- v:
sent = true
default:
} If you want to ask whether it is possible to send a value without actually sending the value, that is inherently racy no matter how it is implemented. |
@ianlancetaylor |
Oh, sorry, you meant sending on a closed channel. That is typically a logic error. Clearly there are already ways to do this where it is required, such as a mutex. I don't think it's necessary to modify the language to make it easier to handle. |
Currently, map access and type assertions have way to detect unsafe operations before causing runtime panic.
I propose extending the syntax for all operations that may cause runtime panic.
Proposal
is equivalent to
is equivalent to
is equivalent to
is equivalent to
is equivalent to
no equivalent syntax now.
After defining above semantics, we can define another one.
is equivalent to
Motivation
I think 'deep checking' example explains the situation.
To write correct code, to review somebody's code,
We have to consider array/slice bounds check, null check, ..., etc.
Those boilerplate are verbose and error prone still today.
The only important question for this kind of problem is 'Is the target attribute accessible or not?'.
The new semantics answer that question clearly without any noise.
We can guarantee that code works as intended without knowing details.
Thank you for reading.
The text was updated successfully, but these errors were encountered: