Skip to content

proposal: Go 2: accept multiple return values as the last arguments to function calls #40387

@ysmood

Description

@ysmood

description:

I did some research, but can't find a similar issue, so I opened a new one.

Sometimes we really want to use the returned values as the input of another function directly without having to use tmp vars.

For example:

package main

func input() (int, int) { return 0, 0 }

func foo(a, b int) {}

func bar(a, b, c int) {}

func main() {
	tmp1, tmp2 := input()
	bar(0, tmp1, tmp2)
}

It will be great if we can do this:

func main() {
	foo(input())    // this works fine for Go 1
	bar(0, input()) // this doesn't work, make me feel it's a bug of Go, because the previous line works
	bar(input(), 0) // we can discuss whether it's good to support this or not
}

It's useful for simple debugging:

func foo() (int, error)
func bar() (string, error)

func main() {
	fmt.Println(bar())        // currently, we can only do this, the next will cause compile error
	fmt.Println("foo", foo()) // prefix logs to debug
	fmt.Println("bar", bar())
}

We already only allow variadic arguments as last arguments, like this:

func bar(a int, list ...int) {}

func main() {
	list := []int{1,2}
	bar(0, list...)
}

So I think it makes sense for people to support this kind of feature.

The idea is pretty static. For example func foo(int, string, int) can only accept functions like func bar() (string, int). I feel the proposal is too hard to be abused. If you can give me some examples of how to abuse it, that will be great.

I think this language feature doesn't break the GO 1, and won't have an impact on compilation performance.


Here a real-world use case might help you understand it better:

Go already supports it, people use it every day, like this:

func readFile(string) (string, error)

content, err := sentryGuard(readFile(path, content))

My proposal just makes it more intuitive. So we can easily do things like:

func guard(loggerInterface, string, error) (string, error)

// when err happens, report it to something like sentry.io
content, err := guard(sentry, readFile(path))

So I don't have to implement a lot of guard types.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions