Go - The difference between var and func to define a function - go

I'm coming from an Scala background, and in Scala, you could define functions both as a single value, or an actual function, for instance:
val inc1: Int => Int = _ + 1 // single FUNCTION value
def inc2(x: Int): Int = x + 1 // normal function definition
// in this case "inc1 eq inc1" is true, since this is a single instance
// but "inc2 eq inc2" is false
And these 2 have some differences (i.e., size allocation, first one is a single instance, while the other one returns an instance each time it is invoked, ...), so based on the use case, we could kind of reason which one to use. Now I'm new to golang, and wanted to know if the below 2 function definitions (correct me if I'm wrong with the phrase) differ in Golang, and if so, what are differences?
var inc1 = func(x int) int { return x + 1 }
func inc2(x int) int { return x + 1 }
Thanks in advance!

Scala borrows a lot from functional programming. Go does not.
(If you've used multiple other programming languages, you should definitely read the Go specification. It's not very long as Go is not a very large language, although the new generics definitely complicate things a bit.)
In Go, the func keyword introduces a function definition or function type, with the details being context-dependent. The var keyword introduces a variable declaration.1 So:
func inc2(x int) int { return x + 1 }
defines a function, inc2, whose code is as shown. But:
var inc1 = // ...
declares and then initializes a variable, inc1. The type and initial value of the variable are determined by the commented-out section, so:
var inc1 = func(x int) int { return x + 1 }
defines a function (with no name) whose code is as shown. That function is then assigned to the variable as its initial value, so that the implied type of the variable is func (int) int or function taking one argument of type int and returning one value of type int.
Having created a variable, you can now either call the function currently stored in that variable:
func callit(arg int) {
result := inc1(arg)
// ... do something with the result ...
}
Or you can assign a new value into the variable, e.g.:
func overwrite() {
inc1 = func(a int) int { return a * 2 } // name `inc1` is now misleading
}
Because inc2 is a function, you can't re-assign a new value to it: it's just a function, not a variable.
1Note that a variable declaration with an initialization can use the "short declaration" form:
func f() {
v := 3
// ...
}
where we leave out the type and just say "use the type of the expression to figure out the type of the declaration". This declares and initializes the variable. Short declarations can only appear in block scope, so these must be inside some function. Other than omitting the var keyword they do nothing that you couldn't do by including the var keyword, or sometimes multiple var keywords:
result, err := doit()
might require:
var result someType
var err error
result, err = doit()
when written without using the short-declaration form.

Related

Finding the type of a variable through static analysis? [duplicate]

This question already has an answer here:
Golang static identifier resolution
(1 answer)
Closed 4 months ago.
How can I determine the type of a variable through static analysis?
Suppose I have the following code:
func doSomething(x interface{}) {}
func main() {
p := Person()
doSomething(p)
}
And I want to analyze doSomething(person), is it possible to get the type of Person through static analysis?
What if there were multiple levels of assignment?
p1 := Person()
p2 := p1
doSomething(p2)
or
parent := Parent()
p := Parent.Child() // type Person
doSomething(p)
The use case is that I have a generic function that is commonly used throughout the (very large) codebase, and would like to introduce a new type safe version of this function. To do this, I hope to automatically determine the "type" of the function and refactor it accordingly:
// old
DB.InsertRow(person)
// new
Person.InsertRow(person)
Finding the type of an expression through static analysis is non-trivial, and sometimes not possible, for details see Golang static identifier resolution.
The use case is that I have a generic function that is commonly used throughout the (very large) codebase, and would like to introduce a new type safe version of this function. To do this, I hope to automatically determine the "type" of the function and refactor it accordingly:
// old
DB.InsertRow(person)
// new
Person.InsertRow(person)
Just for refactoring purposes, I don't think it is worth the hassle to implement it.
What you may do is change the signature of DB.InsertRow() temporarily to accept only a specific type such as int or your custom type you're sure is not used anywhere (e.g. type tempFoo struct{}).
To what end? Doing so, the compiler will do the hard work for you. You will see error messages showing exactly the types your codebase is trying to pass to DB.InsertRow(), so I'd say mission accomplished.
For example this code compiles:
func doSomething(x interface{}) {}
func main() {
doSomething(image.Pt(1, 2))
doSomething("abc")
doSomething(image.Rect) // image.Rect is a function which we don't call,
// so we're passing a value of a function type here
}
If we change doSomething():
func doSomething(x int) {}
We get the types we're seeking for from the compiler:
./prog.go:10:14: cannot use image.Pt(1, 2) (value of type image.Point) as type int in argument to doSomething
./prog.go:11:14: cannot use "abc" (untyped string constant) as int value in argument to doSomething
./prog.go:12:14: cannot use image.Rect (value of type func(x0 int, y0 int, x1 int, y1 int) image.Rectangle) as type int in argument to doSomething
Using the advice from Golang static identifier resolution to use golang.org/x/tools/go/types, I found that this was pretty straight forward to do with the golang.org/x/tools/go/analysis package, which has the types info available alongside the parsed ast.
This was my solution:
package rewriter
import (
"go/ast"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
func run(pass *analysis.Pass) (interface{}, error) {
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
(*ast.CallExpr)(nil),
}
inspect.Nodes(nodeFilter, func(node ast.Node, push bool) bool {
callExpr, ok := node.(*ast.CallExpr)
if !ok {
return true
}
funcExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
// check method name
if funcExpr.Sel.Name != "doSomething" {
return true
}
for _, arg := range callExpr.Args {
// lookup type of the arg
argType := pass.TypesInfo.Types[arg].Type
if argType.String() == "*rewriter.Person" {
// do whatever you want here
}
}
return false
})
return nil, nil
}
One can augment this to look at the receiver of the method and add refactoring logic as needed (using analysis.Diagnostic).

Naming receiving variables from a multiple return function

Go allows for multiple named return values, but what about the receiving variables? Are they protected when return values are juggled around?
Let's say we start with this:
func foo() (i int, j int) {
i = 1
j = 2
return
}
a, b := foo()
Now what if some other coder comes by and makes the following change to foo's definition:
func foo() (j int, i int) {
my calling function is invalidated. Is it, then, possible to name the returned values from the calling side as well. For instance, if I called it like this:
(a:i, b:j) := foo()
then I would be attaching them to the named return values, rather than assigning them in the order they are returned.
So, is there a way to solve that problem?
This is no different than rearranging the input parameters. As a rule, don't do that unless you intend to make a breaking change. But if you want to deal with things by name rather than position, you want a struct. For example, you can use anonymous structs:
func foo() struct {
i int
j int
} {
return struct {
i int
j int
}{1, 2}
}
func main() {
result := foo()
fmt.Println(result.i, result.j)
}
Of course you can also name the struct if you used it in other places, but there's no need if you just want to name the fields.

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.

Go resetting closure variable

I came upon an example of closures in Go here:
https://gobyexample.com/closures
It gives a pretty straight-forward example of closure scoping in Go. I changed how i is initialized from "i := 0" to "i := *new(int)".
func intSeq() func() int {
i := *new(int)
return func() int {
i += 1
return i
}
}
func main() {
// We call `intSeq`, assigning the result (a function)
// to `nextInt`. This function value captures its
// own `i` value, which will be updated each time
// we call `nextInt`.
nextInt := intSeq()
// See the effect of the closure by calling `nextInt`
// a few times.
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
// To confirm that the state is unique to that
// particular function, create and test a new one.
newInts := intSeq()
fmt.Println(newInts())
}
The output of this is still 1, 2, 3, 1. Does the variable 'i' in intSeq() not get reallocated everytime nextInt() in main() is called?
Take a look at how you implemented intSeq.
func intSeq() func() int {
i := *new(int)
return func() int {
i += 1
return i
}
}
The initialization of i is outside of the function it returns.
So the only time a new pointer is allocated is when you actually call intSeq.
Since you are doing that just two times, that's how many different pointers you got.
That explains why the value is not reset when you just call nextInt (note that executing nextInt means just executing the function returned, which looks like:
func() int {
i += 1
return i
}
That would not reset the value of i but rather keep incrementing it (until you create a new one by calling intSeq again).
I hope that clarifies.
No it doesn't. That's the point of the closure. You are initializing an integer variable and storing it on the heap for use by the function the intSeq() function returns. There is no variable initialization happening in the nextInt() function
You will get a new function that uses a new sequence counter starting at 0 for each call to intSeq()
Edit: to add to this this is a bad way to get the current behavior. A better way would be to create a new sequence type that contains the method nextInt() int. E.g.:
type Sequence struct {
counter int
}
func (s *Sequence) nextInt() int {
s.counter++
return s.counter
}
func main() {
intSeq := new(Sequence)
fmt.Println(intSeq.nextInt())
fmt.Println(intSeq.nextInt())
fmt.Println(intSeq.nextInt())
}
There is no point in doing i := *new(int). That line says:
Allocate a new int
Create a pointer to it
Dereference the pointer
Assign the value to i
This is no different from i := 0 or var int i, but there's the extra step in the middle of creating, dereferencing, and discarding the pointer that never gets used.
If you want a pointer to an int, use i := new(int). *new anywhere is a pointless invocation and a code smell.

Use one return value?

I want to call my function test and use one of the return values. How do I say give me the first or second value? I thought the below would give me "one" but [1] is incorrect usage causing a compile error
package main
import (
"fmt"
)
func test() (int, string) { return 1, "one"; }
func main() {
i,sz:=test()
fmt.Printf("%d=%s\n",i,sz)
fmt.Printf("%s", test()[1]) //error
}
As far as I know, you can't subscript function return values. You can do:
_, someString := test();
fmt.Println(someString);
Citing the Go Language Specification:
A primary expression of the form a[x]
denotes the element of the array, slice, string or map a indexed by x. The value x is called the index or map key, respectively. [...] Otherwise [if a is not an array, slice string or map] a[x] is illegal.
Multiple return values in Go, however, are not arrays being returned, but a separate language feature. This must be so, because an array can only hold elements of a single type, but return values can be of different types.
But since return values are not arrays (or slices, strings or maps), the a[x] syntax is, per language spec, a syntax error. As a result, as #dav has already correctly stated, you will have to actually assign the return value to a variable in order to use it elsewhere.
In special cases, you may be able to use this bit of trivia to avoid variable assignment:
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order.
Which makes the following possible:
func foo() (int, string) {
return 42, "test";
}
func bar(x int, s string) {
fmt.Println("Int: ", x);
fmt.Println("String: ", s);
}
func main() {
bar(foo())
}

Resources