How to get return type of a function - go

I'm writing higher order functions in Go, and am trying to figure out the return type of the inner function f.
As a simple example, let's say I want to return the default value of the return type of the inner function:
if f returns string, GetDefault(f) returns ""
if f returns []byte, GetDefault(f) return []byte{}
func GetDefault(func(interface{})) {
// How would I write this function?
}
Is it possible to write such a function in Go, without running f?

You can use reflection to get the type and initialize a default value.
func GetDefault(f interface{}) interface{} {
ft := reflect.TypeOf(f)
if ft.Kind() != reflect.Func {
panic("not a func")
}
out0 := ft.Out(0) // type of the 0th output value
return reflect.New(out0).Elem().Interface()
}
https://play.golang.org/p/BhevFvsut5z

Related

Return default value for generic type

How do you return nil for a generic type T?
func (list *mylist[T]) pop() T {
if list.first != nil {
data := list.first.data
list.first = list.first.next
return data
}
return nil
}
func (list *mylist[T]) getfirst() T {
if list.first != nil {
return list.first.data
}
return nil
}
I get the following compilation error:
cannot use nil as T value in return statement
You can't return nil for any type. If int is used as the type argument for T for example, returning nil makes no sense. nil is also not a valid value for structs.
What you may do–and what makes sense–is return the zero value for the type argument used for T. For example the zero value is nil for pointers, slices, it's the empty string for string and 0 for integer and floating point numbers.
How to return the zero value? Simply declare a variable of type T, and return it:
func getZero[T any]() T {
var result T
return result
}
Testing it:
i := getZero[int]()
fmt.Printf("%T %v\n", i, i)
s := getZero[string]()
fmt.Printf("%T %q\n", s, s)
p := getZero[image.Point]()
fmt.Printf("%T %v\n", p, p)
f := getZero[*float64]()
fmt.Printf("%T %v\n", f, f)
Which outputs (try it on the Go Playground):
int 0
string ""
image.Point (0,0)
*float64 <nil>
The *new(T) idiom
This has been suggested as the preferred option in golang-nuts. It is probably less readable but easier to find and replace if/when some zero-value builtin gets added to the language.
It also allows one-line assignments.
The new built-in allocates storage for a variable of any type and returns a pointer to it, so dereferencing *new(T) effectively yields the zero value for T. You can use a type parameter as the argument:
func Zero[T any]() T {
return *new(T)
}
In case T is comparable, this comes in handy to check if some variable is a zero value:
func IsZero[T comparable](v T) bool {
return v == *new(T)
}
var of type T
Straightforward and easier to read, though it always requires one line more:
func Zero[T any]() T {
var zero T
return zero
}
Named return types
If you don't want to explicitly declare a variable you can use named returns. Not everyone is fond of this syntax, though this might come in handy when your function body is more complex than this contrived example, or if you need to manipulate the value in a defer statement:
func Zero[T any]() (ret T) {
return
}
func main() {
fmt.Println(Zero[int]()) // 0
fmt.Println(Zero[map[string]int]()) // map[]
fmt.Println(Zero[chan chan uint64]()) // <nil>
}
It's not a chance that the syntax for named returns closely resembles that of var declarations.
Using your example:
func (list *mylist[T]) pop() (data T) {
if list.first != nil {
data = list.first.data
list.first = list.first.next
}
return
}
Return nil for non-nillable types
If you actually want to do this, as stated in your question, you can return *T explicitly.
This can be done when the type param T is constrained to something that excludes pointer types. In that case, you can declare the return type as *T and now you can return nil, which is the zero value of pointer types.
// constraint includes only non-pointer types
func getNilFor[T constraints.Integer]() *T {
return nil
}
func main() {
fmt.Println(reflect.TypeOf(getNilFor[int]())) // *int
fmt.Println(reflect.TypeOf(getNilFor[uint64]())) // *uint64
}
Let me state this again: this works best when T is NOT constrained to anything that admits pointer types, otherwise what you get is a pointer-to-pointer type:
// pay attention to this
func zero[T any]() *T {
return nil
}
func main() {
fmt.Println(reflect.TypeOf(zero[int]())) // *int, good
fmt.Println(reflect.TypeOf(zero[*int]())) // **int, maybe not what you want...
}
You can init a empty variable.
if l == 0 {
var empty T
return empty, errors.New("empty Stack")
}

How to combine two return params into one value

What I have many times in different versions in my code:
func f() (bool, bool) {
value, successFulOperation := someStuff()
return value, successFulOperation
}
// somewhere else
value, successfulOperation := f()
if value && successfulOperation {
// do stuff
}
// do stuff should only be executed if value is true AND the operation that retrieved value succeeded without an error. In other words: I don't care about value or successfulOperation. I only care about value && successfulOperation.
A solution I want to avoid (seems verbose):
value, successfulOperation := f()
actualValue := value && successfulOperation
if actualValue {...}
Above code is really simplified. In reality the if conditions will be nested and more complicated.
What I want:
A wrapper for f that combines both values into one. How do I do that? The solution should work for any function taking any parameters and returning two bools.
The following does not work:
type doubleBoolFunc func(...interface{}) (bool, bool)
func and(fn doubleBoolFunc, params ...interface{}) bool {
b1, b2 := fn(params...)
return b1 && b2
}
actualValue := and(f())
You can't write a wrapper function to turn the two bools into one until generics are in the language in go 1.181. Or at least you can, using reflect, but it's a mess.
But you can write this with go 1.17:
func both(x, y bool) bool {
return x && y
}
func f() (bool, bool) {
return true, false
}
func main() {
r := both(f())
fmt.Println(r)
}
But more practical (in my opinion) is to eschew this complication, and use a 1-line if. Not everything needs to be a function or abstracted away:
if a, b := f(); a && b {
...
}
[1] Even when generics are introduced in go 1.18, I don't think there'll be a way to specific a generic type that represents a function with arbitrary arguments that returns two bools.
func and(a, b bool) bool {
return a && b
}
then if f return 2 bool
value := and(f())
will work
To fix the code at the end of your question, don't invoke the function f(), simply reference the function name f and then list its args:
// actualValue := and(f(args...))
actualValue := and(f, args...)
https://go.dev/play/p/KAT2L58ZQy3

Golang: Best way to evaluate a function once in a specific case

Suppose, I have a Eval struct and multiple goroutines can call its Evaluate method to get the value of the result field. Following is the basic structure of code:
type Eval struct {
done bool
result interface{}
}
func (e *Eval) Evaluate(f func() interface{}) interface{} {
if e.done == false {
e.result = f()
e.done = true
}
return e.result
}
As the function passed as argument of Evaluate method can take quite some time to execute, so I want to prevent calling that function multiple times. Only the first goroutine to call the Evaluate function will actually "evaluate" the value of result. The other goroutines will simply wait for the result field to be ready.
Here is what I came up with:
type Eval struct {
mu *sync.Mutex
cond *sync.Cond // cond uses mu as sync.Locker
once *sync.Once
done bool
result interface{}
}
func (e *Eval) Evaluate(f func() interface{}) interface{} {
go e.once.Do(func() {
defer e.cond.Broadcast()
v := f()
e.mu.Lock()
e.result = v
e.done = true
e.mu.Unlock()
})
e.mu.Lock()
if e.done == false {
e.cond.Wait()
}
v := e.result
e.mu.Unlock()
return v
}
But I feel like it is an overkill and using a sync.Mutex to control access to a variable that will be written once and read many times is not the efficient solution. What is the best and most "golang" way to achieve what I want?
Edit: As mentioned in comment, only using sync.Once does the job.

How to spread arguments as parameters

I have the following Golang code:
rows, err := common.GetAll(c, req, params, timer)
return common.GenericRowMarshal(200, rows, err)
I want to figure out if it's possible to do:
return common.GenericRowMarshal(200, common.GetAll(c, req, params, timer)...)
but this doesn't compile :(
It says "not enough arguments to call..."
Anyone know if this is possible somehow?
No, each time a statement executes, the function value and parameters to the call are evaluated as usual, see doc:
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. The call of f must contain no parameters other than the call of g, and g must have at least one return value. If f has a final ... parameter, it is assigned the return values of g that remain after assignment of regular parameters.
func Split(s string, pos int) (string, string) {
return s[0:pos], s[pos:]
}
func Join(s, t string) string {
return s + t
}
if Join(Split(value, len(value)/2)) != value {
log.Panic("test fails")
}
If f has a final ... parameter, it is assigned the return values of g that remain after assignment of regular parameters.
For example, the following code works:
package main
import "fmt"
func main() {
f(200, g())
}
func f(i int, slice ...interface{}) {
fmt.Println(i, slice) // 200 [[1 <nil>]]
}
func g() []interface{} {
return []interface{}{1, nil}
}
I've tried this too, thinking it might work. Currently (Go 1.13) you can only do this if the inner func returns exactly the parameters that the outer function expects.

Function types in Go - particular type casting to more general type

What cast / assertion need I do in Go in order to pass to a function expecting a generic function like func(interface{}) interface{}, a more specific function like func(int) int instead?
For example, in code like this, fooA can be passed to MakeExclamer, but not fooB:
func MakeExclamer(foo func (interface{}) interface{}, n int) func () {
return func() {
fmt.Printf("%v!!!", foo(n))
}
}
func fooA(x interface{}) interface{} {
return x.(int)*2
}
func fooB(x int) int {
return x * 10
}
func main() {
exclamerA := MakeExclamer(fooA, 12)
exclamerA()
exclamerB := MakeExclamer(fooB, 66)
// >> cannot use fooB (type func(int) int) as type func(interface {}) interface {} in argument to MakeExclamer
exclamerB()
}
(Go Playground link: https://play.golang.org/p/xGzfco0IAG)
I'm not interested much in alternative code structure patterns, since this is how I want it to work: a specific function should be passed to a general function transformer (accepting function of type Any -> Any) that will return another general function (Any -> Any). This may not be idiomatic in Go, but it is the pattern that I want my code to follow.
To use type assertions, every possible type must be enumerated in MakeExclamer:
func MakeExclamer(fn interface{}, arg interface{}) func() {
switch fn := fn.(type) {
case func(int) int:
return func() {
fmt.Printf("%v!!!\n", fn(arg.(int)))
}
case func(interface{}) interface{}:
return func() {
fmt.Printf("%v!!!\n", fn(arg))
}
default:
panic("not supported")
}
}
To accept a function of any type, the fn argument is declared as type interface{}. The code uses a type switch to handle the different function types.
playground example
Reflection can be used to write a more general function.
func MakeExclamer(fn interface{}, arg interface{}) func() {
fnr := reflect.ValueOf(fn)
argr := reflect.ValueOf(arg)
return func() {
resultr := fnr.Call([]reflect.Value{argr})
fmt.Printf("%v!!!\n", resultr[0].Interface())
}
}
playground example
First things first : When it comes to typing in Go, everything is theoretically possible. That's because even though the compiler does a lot of checks at compile-time, it is possible to change the runtime... at runtime. So-called runtime hacks, where you dynamically manipulate runtime structs that you're NOT supposed to handle.
Now, you have an interesting question, whose answer doesn't include the need to use the 'unsafe' package. However, the way I found of generalizing a function involves heavy reflection.
How to call a function (via reflection) ?
The documentation for the reflect package can be found here.
So, like all elements in Golang, functions have a Type. Without going through all fields, functions do take an array of arguments and produce an array of results. It is possible to investigate the Type of arguments and results through the In(int) and Out(int) method.
func investigate(fn interface{}) {
fnType := reflect.TypeOf(fn)
for idx := 0; idx < fnType.NumIn(); idx ++ {
fmt.Printf("Input arg %d has type %v\n", idx, fnType.In(idx))
}
for idx := 0; idx < fnType.NumOut(); idx ++ {
fmt.Printf("Output arg %d has type %v\n", idx, fnType.Out(idx))
}
}
We won't use this code. However, two important things are to be noted at this point :
The generic type under which a function can be passed around without caring about its type is interface{}. Something like "func(interface{}) interface{}" is not a generalization of a function, it is already a concrete type. Hence, "func(interface{}) interface{}" is not a generalization of "func(int) int", those are two different function types entirely. This is why you can't use type assertions/cast to convert from one function type to another.
A function can be represented as something that takes an input array and produces and output array.
Now, in order to call a function, you have to get not its Type, but its Value. Once you get its value, you can call it using an array of arguments, which must all be Values.
The prototype is:
func (v Value) Call(in []Value) []Value
Using this method, it is possible to call any function.
The code
So, the only thing you need is to convert whichever arguments array you have to an array of Values, then you will be able to call your function.
Here is your code:
package main
import (
"fmt"
"reflect"
)
func MakeExclamer(foo interface{}, n int) func() {
exclamer := generalize(foo, n)
return func() {
fmt.Printf("%v!!!\n", exclamer())
}
}
func fooA(x interface{}) interface{} {
return x.(int) * 2
}
func fooB(x int) int {
return x * 10
}
func generalize(implem interface{}, args ...interface{}) func() interface{} {
valIn := make([]reflect.Value, len(args), len(args))
fnVal := reflect.ValueOf(implem)
for idx, elt := range args {
valIn[idx] = reflect.ValueOf(elt)
}
ret := func() interface{} {
res := fnVal.Call(valIn)
// We assume the function produces exactly one result
return res[0].Interface()
}
return ret
}
func main() {
exclamerA := MakeExclamer(fooA, 12)
exclamerA()
exclamerB := MakeExclamer(fooB, 66)
exclamerB()
}
Playground
The important bit is the generalize function which makes the translation between your arguments and an array of Values, then returns a new function whith all parameters already filled.
Do not hesitate if you need any precision !

Resources