Is it possible to get a single value from a function (which has multiple return values) during a statement? - go

Lets say for example add(int, int) returns and int and an error, and I want to append the int return value into a string. The way I know how to do it in go is:
foo := ""
bar, _ := add(1, 2)
foo += strconv.Itoa(bar)
However, if add() didn't return an error variable, I can just do foo += strconv.Itoa(add(1, 2)).
Is it possible to ignore the error variable during the statement to do something like that?

Is it possible to ignore the error variable during the statement to do something like that?
No, Go offers no language construct for something like this.
(But you can have your own Must... functions like you'll find in package regexp or text/template.)

Disclaimer (my opinion): This answer is just for fun. I don't recommend ever using this. Ignoring errors is bad, and trying to compactify every line of code is a fool's errand. This just illustrates some interesting concepts about how Go handles multiple return values, and I learned something new while writing this, so I thought I'd share.
Related: The more practical cousin of this problem is the "Must pattern", used by some of the standard library including templates. It involves taking a value and an error, panicing if the error is not nil, and then returning the value. See this (currently frozen) proposal
You need a wrapper function to do this. The multiple return values will automatically expand to fill the arguments.
See this example which matches the types of add()
func ignoreError(i int, err error) int {
return i
}
Calling:
foo := ""
foo += strconv.Itoa(ignoreError(add(1, 2)))
Here's a more general alternative, which will take any number of values from another function and return the first.
func takeFirstValue(v ...interface{}) interface{} {
if len(v) == 0 {
return nil
}
return v[0]
}
Calling:
foo := ""
foo += strconv.Itoa(takeFirstValue(add(1, 2)).(int))
This option requires casting at the call site .(int) to restore the data type, as takeFirstValue returns interface{}.

Related

Return only the first result of a multiple return values in golang

Absolute newbie question here.
Some functions in Go return more than one value (normally, the value and an error). I was writing a func who return the return value of one of those functions, and even if it is very easy to put the values on variables and return only the first one, I have the doubt if I could do the same in only one line without the extra variable. This is something often uses in other languages like C, Java, C#, Ruby, etc
func someFunc (param string) int {
// do something with the string, not very important
return strconv.Atoi(param)
}
I know this works
func someFunc (param string) int {
// do something with the string, not very important
var result int
result, _ = strconv.Atoi(param)
return result
}
It is this possible in Go? It is considered a "good practice" (like in Java*)
Note: Before someone say that this technique is not a good practice in Java, clarify that is not important for the question, but some people (like the ones in the company I work) encourage that style.
Use a short variable declaration for the shortest code to accomplish this goal:
func SomeFunc(parm string) int {
result, _ := strconv.Atoi(param)
return result
}
There is no one line solution without introducing a helper function that accepts two arguments and returns the first. One of these helper functions would be needed for each combination of types where you want to ignore a value.
Your best possible one-liner is a helper function written as:
func first(n int, _ error) int {
return n
}
func SomeFunc(param string) int {
return first(strconv.Atoi(param))
}
Note that:
the argument types and positions must match exactly
the second argument to first has the blank identifier (_), making it clear that you wish to completely ignore it. [1]
If you absolutely don't want to declare a named function, you may use a function literal, but that looks real ugly:
func SomeFunc(param string) int {
return func(n int, _ error) int { return n }(strconv.Atoi(param))
}
In general, the helper function is worth it if you have a lot of repetition in your code. Otherwise just use a temp variable, which looks clean and idiomatic:
func SomeFunc(param string) int {
n, _ := strconv.Atoi(param)
return n
}
Playground: https://play.golang.org/p/X8EOh_JVDDG
Once generics will be added to the language in Go 1.18, you will be able to write a helper function that can be used with any return pair and preserve type safety on the first one:
func first[T, U any](val T, _ U) T {
return val
}
func SomeFunc(param string) int {
return first(strconv.Atoi(param))
}
Go2 Playground: https://go2goplay.golang.org/p/vLmTuwzrl5o
Footnotes:
[1] Keep in mind that in case of strings.Atoi the second return value is an error, and ignoring errors is bad practice. However there are cases where the success of the operation truly doesn't matter, then it's fine to use _ to ignore the argument.

Return input variables in golang

I just got started with Golang, and I saw the typical swap function example:
func swap(x, y string) (string, string) {
return y, x
}
I automatically thought that the named returns could have solved it and that it was a sweeter example, so I tried the shorter version:
package main
import "fmt"
func swap(z, y int) (z, y int) {
return
}
func main() {
fmt.Println(swap(2, 3))
}
But to by my surprise it didn't compile complaining about a duplicate argument. Why is not possible to return an input argument? Am I doing something wrong or it is just not supported?
I thought this was a totally valid use case and that it could have been many other examples for this usage.
I'm also a Golang beginner. Here's what I managed to find out.
The problem is essentially, that you declare two variables named z, then expect them to be unified. This is not supported, and in fact would go against the main goal of named return types, which is to document the meaning of the values returned.
To explain in more detail, this is a bit like writing the following code:
func badFunction(a int) int {
var a int = 0
return a
}
A variable is declared twice, and this is confusing for Go. If we look at what the 'tour of go' has to say about named return values, we can see the issue. It's not the greatest source, but it's a source nonetheless:
Go's return values may be named. If so, they are treated as variables defined at the top of the function.
That is to say, your example is almost exactly like badFunction. To the compiler, it looks a bit like this:
func swap(a, b int) (int, int) {
var a int = 0
var b int = 0
return b, a
}
Naturally, the compiler complains about a redeclared in block, which is a related though admittedly not equal error. The error message you receive there appears to essentially be a pre-check to prevent the user from seeing the code produced when desugared.
As this Stackoverflow question reports, named return values should essentially be for documentation only. However, it does mention the possibility of accidental shadowing. It may be that an earlier Go version supported this, but has since been changed to prevent bugs due to this kind of name collision, however I have not found anything pertaining to this.
The effective go section on the topic also has something to say:
The return or result "parameters" of a Go function can be given names and used as regular variables, just like the incoming parameters. When named, they are initialized to the zero values for their types when the function begins; if the function executes a return statement with no arguments, the current values of the result parameters are used as the returned values.
The names are not mandatory but they can make code shorter and clearer: they're documentation.
TL;DR: The compiler doesn't unify names in the way you might expect. This kind of implicit shadowing not supported, and should be actively avoided to prevent certain easily avoidable bugs.
I guess problem is not in returning input argument, but in names duplication: y and z are declared twice on the same level and compiler cannot distinguish.
When you declare a variable in return type, Go compiler would consider that, you are declaring the variable there for future use.
Now when the compiler sees the same variable name in both input & return part, it will report a duplicate argument issue.
You can try the working example below, if you want to
func swap(x, y string) (a string, b string) {
a = y
b = x
return
}
You can do this way
func checkError(err *error) (bool, *error) {
if err != nil {
return false, err
} else {
return false, nil
}
}
or if you really want to use variable, this way
func checkError(err *error) (result bool, err_msg *error) {
if err != nil {
return false, err
} else {
return false, nil
}
}

Empty return in func with return value in golang [duplicate]

This question already has answers here:
How does defer and named return value work?
(3 answers)
Closed 5 years ago.
I was reading some code written in Golang on Github and found a very interesting piece of code. I simplified it to be clear.
func Insert(docs ...interface{}) (err error) {
for i := 0; i < 3; i++ {
err = fmt.Errorf("")
if err.Error()!="EOF" {
return
}
}
return
}
I'm very confused about empty return here... How it works? Does he return nil as error or breaks for loop? I understand that this question looks dummy, but I cannot find any info on this in go docs... Also, I don't understand how we can return err, which is, as I understood, declared somehow in return. Does (err error) means that we already have an error variable available in our func which is used as default return value if none specified? Why then we implicitly make return err at the end of func?
I'll be very gratefull for explanation.
The function uses a "named" return value.
From the spec on return statements:
The expression list may be empty if the function's result type
specifies names for its result parameters. The result parameters act
as ordinary local variables and the function may assign values to them
as necessary. The "return" statement returns the values of these
variables.
Regardless of how they are declared, all the result values are
initialized to the zero values for their type upon entry to the
function. A "return" statement that specifies results sets the result
parameters before any deferred functions are executed.
Using named returns allows you to save some code on manually allocating local variables, and can sometimes clean up messy if/else statements or long lists of return values.
func a()(x []string, err error){
return
}
is really just shorthand for
func a() ([]string,error){
var x []string
var err error
return x,err
}
Its a bit shorter, and I agree that it may be less obvious.
Named returns are sometimes needed, as it allows things like accessing them inside a deferred function, but the naked return is just syntactic sugar as far as I can tell, and is never strictly required.
One place I see it commonly is in error return cases in functions that have many return values.
if(err != nil){
return
}
return a,b,c,nil
is easier than
if(err != nil){
return nil,nil,nil,err
}
return a,b,c,nil
when you have to write it a bunch of times. And you don't have to modify those returns if you change the signature to have additional "real" return values.
Most places I am using them in the codebase I just searched, they definitely seem to be hiding other smells, like overly complex multi-purpose functions, too deep if/else nesting and stuff like that.
Go's return values may be named. If so, they are treated as variables defined at the top of the function.
package main
import "fmt"
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
func main() {
fmt.Println(split(17))
}
https://tour.golang.org/basics/7
When you have a named return value (err here):
func Insert(docs ...interface{}) (err error) {
This creates a function-local variable by that name, and if you just call return with no parameters, it returns the local variable. So in this function,
return
Is the same as, and implies,
return err
This is detailed in the tour and in the spec.

Go: abstract iterable

Suppose I want to have a method that should either return a chan or a slice. For example, I need a chan if I want to "follow" a file as new lines come, and a slice if I just want to read and return existing lines.
In both cases I will only have to iterate through this return value. Here is an abstract example in Python (which has nothing to do with files but sort of shows the idea):
def get_iterable(self):
if self.some_flag:
return (x for x in self.some_iterable)
return [x for x in self.some_iterable]
def do_stuff(self):
items = self.get_iterable()
for item in items:
self.process(item)
Now, I have a difficulty doing this in Go. I suppose I should look for something like an "iterable interface" which I should return, but I failed to google up some ready-to-use solutions (sorry if it's just my poor googling skills).
What is the best way to do what I want? Or, maybe, the whole design is "bad" for Go and I should consider something else?
Or, maybe, the whole design is "bad" for Go and I should consider something else?
While you could build some interface on top of the types so that you can deal with them as if they were the same I would say it's a poor choice. The far simpler one is to take advantage of multiple return types and define your func with chan myType, []myType, error for it's return then just use 3 way if-else to check for error, followed by chan or slice. Read of the channel like you normally would, iterate the slice like you normally would. Put the code that does work on myType in a helper method so you can call it from both control flows.
My money says this is no more code and it's also far more straight forward. I don't have to read through some abstraction to understand that I have a channel and the inherit complications that come along with it (chan and a slice are incongruous so trying to model them the same sounds like a nightmare), instead you just have an extra step in the programs control flow.
I'm kinda late to the party, but if you really need some "abstract iterable", you could create an interface like this:
type Iterable interface {
Next() (int, error)
}
(Inspired by sql.Rows.)
Then, you could use it like this:
for n, err := iter.Next(); err != nil; n, err = iter.Next() {
fmt.Println(n)
}
For iteration I usually follow pattern found in sql.Rows and bufio.Scanner. Both have a next-equivalent function returning bool, indicating whether next item has been successfully fetched. Then there's a separate method to access the value and error. This pattern lets you write very clean for loops without complex conditions (and without using break or continue statements) and moves error handling outside of the loop.
If you were to abstract your line input, you could for example create an interface like this:
type LineScanner interface {
Scan() bool
Text() string
Err() error
}
This would give you and abstract line source reader. As a bonus, by using exactly these method names you would make bufio.Scanner instantly implementing your interface, so you could use it along with your own types, for example tail-like reader mentioned in your question.
Fuller example:
package main
import (
"bufio"
"fmt"
"strings"
)
type LineScanner interface {
Scan() bool
Text() string
Err() error
}
func main() {
var lr LineScanner
// Use scanner from bufio package
lr = bufio.NewScanner(strings.NewReader("one\ntwo\nthree!\n"))
// Alternatively you can provide your own implementation of LineScanner,
// for example tail-like, blocking on Scan() until next line appears.
// Very clean for loop, isn't it?
for lr.Scan() {
// Handle next line
fmt.Println(lr.Text())
}
// Check if no error while reading
if lr.Err() != nil {
fmt.Println("Error:", lr.Err())
}
}
http://play.golang.org/p/LRbGWj9_Xw

Compare function values in Go

Normal use of function variables in Go allows them to be compared only to nil, not to one another. The reason for this (as it's been explained to me) is that, since Go has closures, the definition of equality is fuzzy. If I have two different closures with different values bound to local variables, but which use the same underlying function, should they be considered equal or unequal?
However, I do want to be able to make such a comparison. In particular, I have code like this (except, in my real code, the check is actually necessary - this is just a dummy example), where I compare a function pointer to a function literal:
func getFunc(which bool) (func ()) {
if which {
return func1
} else {
return func2
}
}
func func1() { }
func func2() { }
f := getFunc(true)
if f == func1 {
fmt.Println("func1")
} else {
fmt.Println("func2")
}
Is there any way, for example using the reflect or unsafe packages, to get this to work?
You could compare the functions by name:
f := getFunc(true)
f1 := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
f2 := runtime.FuncForPC(reflect.ValueOf(func1).Pointer()).Name()
if f1 == f2 {
fmt.Println("func1")
} else {
fmt.Println("func2")
}
But this relies on both the reflect and runtime packages. Probably not a good idea to do this.
Do you really need to compare functions? I would consider an alternative if possible.
Extending upon #Luke's answer, it appears that I can directly test pointer equality. Note that this is really iffy. To quote the reflect.Value.Pointer() documentation:
If v's Kind is Func, the returned pointer is an underlying code
pointer, but not necessarily enough to identify a single function
uniquely. The only guarantee is that the result is zero if and only if
v is a nil func Value.
That said, here's what you can do:
f := getFunc(true)
f1 := reflect.ValueOf(f).Pointer()
f2 := reflect.ValueOf(func1).Pointer()
eq := f1 == f2
Note that I did run a battery of tests (which I had used to regression-test the code that resulted from #Luke's answer) against this new version, and they all passed, which leads me to believe that the warning issued in the reflect documentation may be OK to ignore, but then, ignoring documentation is really never a good idea...
If all the functions you want to compare have the same signature, you could do something like this:
type cmpFunc struct {
f func()
id uint64
}
func (c *cmpFunc) call() { c.f() }
func (c *cmpFunc) equals(other *cmpFunc) { return c.id == other.id }
makeComparable(f func()) *cmpFunc {
return &cmpFunc{f, get_uniq_id()}
}
Where get_uniq_id does what it says on the box. This gets a bit uglier because Go doesn't have () overloading, and it's more or less impossible without generics if you want to do this for functions in general. But this should work pretty well for your purposes.

Resources