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

Open
guonaihong opened this issue Aug 14, 2020 · 8 comments
Open

Suggestion: increase non-blocking writing syntactic sugar #40777

guonaihong opened this issue Aug 14, 2020 · 8 comments

Comments

@guonaihong
Copy link

@guonaihong 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 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.

@guonaihong
Copy link
Author

@guonaihong 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

@guonaihong guonaihong commented Aug 14, 2020

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

@davecheney davecheney commented Aug 14, 2020

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

@networkimprov networkimprov commented Aug 14, 2020

@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

@ianlancetaylor ianlancetaylor commented Aug 14, 2020

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 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 go101 commented Aug 16, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants
You can’t perform that action at this time.