Skip to content
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

Suggestion: increase non-blocking writing syntactic sugar #40777

Closed
guonaihong opened this issue Aug 14, 2020 · 9 comments
Closed

Suggestion: increase non-blocking writing syntactic sugar #40777

guonaihong opened this issue Aug 14, 2020 · 9 comments
Labels
FrozenDueToAge WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.

Comments

@guonaihong
Copy link

guonaihong commented Aug 14, 2020

idea

There are too many codes in golang for Chan to write without blocking. Often write this code, the mood will be depressed

current writing

select {
    case m.err <- err:
    default:
}   

hope, possible writing

m.err <<- err
@davecheney
Copy link
Contributor

davecheney commented Aug 14, 2020

m.err <<- err

Can you write a short code sample that shows how this would be used in the context of a small program. Thank you.

@davecheney davecheney added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Aug 14, 2020
@guonaihong
Copy link
Author

guonaihong commented Aug 14, 2020

To make the chan of go non blocking, you usually need to write the following code.

package main

import (
        "errors"
        "fmt"
)

type message struct {
        err chan error //In concurrency, only the first error is saved
}

func newMessage() *message {
        return &message{err: make(chan error, 1)}
}

func (m *message) writeNoblockingError(err error) {
        select {
        case m.err <- err:
        default:
        }
}

func (m *message) readNoblockingError() error {
        select {
        case err := <-m.err:
                return err
        default:
        }
        return nil
}

func main() {
        m := newMessage()
        m.writeNoblockingError(errors.New("1. error"))
        fmt.Println(m.readNoblockingError())
        fmt.Println(m.readNoblockingError())
}

@guonaihong
Copy link
Author

If you have a short code, it can make things simple and interesting

package main

import (
        "errors"
        "fmt"
)       

type message struct {
        err chan error //In concurrency, only the first error is saved
}       

func newMessage() *message {
        return &message{err: make(chan error, 1)}
}       

func main() {
        m := newMessage()
        m.err <<-errors.New("1. error"))
        fmt.Println(<<-m.err)
        fmt.Println(<<-m.err)
}   

@davecheney
Copy link
Contributor

Thank you for your sample code. I see that in this example this would reduce the need for a helper method to turn the receive into a non blocking receive. My next question will be -- does this help in real code? What is the value of doing a non blocking read? Yes it does not block the caller, but what does that permit the caller to do in a real program?

If you could explain how your proposal would affect programs that use methods like readNoblockingError() that would be useful for me.

Thank you.

@networkimprov
Copy link

@guonaihong I wouldn't invest time on this; the language avoids multiple ways to write things. See #33892.

The best you can do is write it on one line: select { case c <- v: default: }

@ianlancetaylor
Copy link
Contributor

I don't understand how it is possible to use a statement like m.err <<-errors.New("1. error")). In order to use a channel correctly you have to know whether the value is sent or not.

Similarly, for <<-m.err, you have to know whether a value was received.

As a historical note, before Go 1 you could write

    if c <- v {
        fmt.Println("sent value on channel")
    } else {
        fmt.Println("failed to send value on channel")
    }

But we removed that capability because it was unnecessary given the existence of the select statement. https://go.googlesource.com/go/+/19d9a408451662d09b49fe3b0f1971728e28213f%5E%21/#F0

@davecheney
Copy link
Contributor

davecheney commented Aug 15, 2020

I echo @ianlancetaylor point. On paper it is possible to create a new syntax that makes a one line blocking receive into a non blocking one but this introduces another problem. Channel receive is an expression, it must return a value. In both the original example and your <<- syntax this “nothing was available” value was the zero value for the type. It seems to me that the caller would have to inspect this value to know “was a value received or not” and then you’re back to the same level of verbosity as previous, just one level of abstraction removed.

@go101
Copy link

go101 commented Aug 16, 2020

If the type of m.err is a comparable type, then m.err <<- err is a comparison expression.

@seankhliao
Copy link
Member

Duplicate of #34203

@seankhliao seankhliao marked this as a duplicate of #34203 Jun 12, 2022
@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Jun 12, 2022
@golang golang locked and limited conversation to collaborators Jun 12, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Projects
None yet
Development

No branches or pull requests

7 participants