Return input variables in golang - go

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
}
}

Related

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

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{}.

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.

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.

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.

Constants in Go established during init

In my Go program, there are configuration values that I want to be constant for the duration of program execution, but that I want to be able to change at the deployment site. As far as I can tell, there's no way to achieve this with the const keyword, since (again, as far as I can tell) its value must be a constant specified at compile time. This means that the only way to achieve what I want would be to declare normal variables and initialize them during the package's init function. It's not that that won't work, but rather that there will now be nothing to prevent these pseudo-constant's values from changing.
My two questions are:
Am I missing something about how const works?
Assuming I'm not, what's the preferred way to handle this? A public function that returns a private variable that I never expose, never changing it? Just hoping people don't alter the variables, since they're really configuration settings?
Create a file "config.go" and create the vars you want to expose.
Don't export them (make them all lower case). Instead create public (upper case) funcs that give access to each item.
package config
var x = 10
func X() int {
return x
}
When you want those variables you simply import ./config and use them in code as follows:
if config.X()
Obviously, you can set the variables in the package init.
The following code is almost the same as the second method of #Christopher, except that it is not a module, it located in the main package.
package main
import (
"os"
)
type Config struct {
debug bool
key string
proxyNumber int
}
func (c *Config) Debug() bool {
return c.debug
}
func (c *Config) Key() string {
return c.key
}
func (c *Config) ProxyNumber() int {
return c.proxyNumber
}
const (
CONFIG_NAME = "config.ini"
)
var config *Config
func init() {
DefaultConfig()
if Exists(CONFIG_NAME) {
//try to save the config file
}else {
//try to load from the config file
}
}
func DefaultConfig() {
config = &Config{debug:true, key:"abcde",
proxyNumber:5,
}
}
//Exist: check the file exist
func Exists(path string) bool {
_, err := os.Stat(path)
if err == nil { return true }
if os.IsNotExist(err) { return false }
return false
}
you can use config to load and save the config file.
This is a very good question because it delves into what I suspect may be an omission from Go - immutable state.
From the language reference, "constant expressions may contain only constant operands and are evaluated at compile-time."
You cannot make vars constant, which is a shame. Joe's answer proposes encapsulation as a solution, which will work well - but it's verbose, tedious and might introduce errors.
By comparison, many impure functional languages combine mutable variables with single-assignment immutable values. For example, Scala has the keywords 'val' and 'var'; the meaning of Scala's 'var' is quite similar to Go's 'var'. Immutability is a useful tool in the toolbox because referentially-transparent side-effect-free functions can be written, alongside stateful mutable procedural code. Both have their place. Immutability is also an valuable tool for concurrency because there is no worry about possible race conditions if immutable values are shared between goroutines.
So in my opinion, amongst its many strengths, this is one of Go's shortcomings. It would presumably not be hard to support vals as well as vars, the difference being that the compiler checks that each val is assigned exactly once.
Until that feature is added, you have encapsulation as your only option.
You can do something like this:
package main
import (
"fmt"
"strconv"
)
var a string
func main() {
myvar, err := strconv.Atoi(a)
if err != nil {
fmt.Println(err)
}
fmt.Println(myvar)
}
and compile the program with
go build -ldflags '-X main.a 10' test.go
That way you can define a constant during compile time.
Just use standard go flags with iniflags. Standard go flags allow setting arbitrary config variables at program start via passing command-line flags, while iniflags "magically" add support for reading config variables from ini files.
You can wrap the variable in a function that returns its value:
func genConst(x int) func() int {
return func() int {
return x
}
}
var Constx = genConst(5)
var x1 = Constx()
This way the value cannot be changed by accident, even in the file where it's defined

Resources