Examining the signature of function assigned to an interface{} variable using reflection - reflection

I'm trying the build a generic currying function that's look like:
package curry
import (
"fmt"
"reflect"
)
// Function
type fn interface{}
// Function parameter
type pr interface{}
// It return the curried function
func It(f fn, p ...pr) (fn, error) {
// examine the concret type of the function f
if reflect.ValueOf(f).Kind() == reflect.Func {
// Get the slice of input and output parameters type
} else {
return nil, fmt.Errorf("%s", "takes a function as a first parameter")
}
// _, _ = f, p
return nil, nil
}
Is it possible to extract the slice of input and output parameters types as []reflect.Type of the function f ?

You can use reflect.Type.In(int) and reflect.Type.Out(int), there are corresponding methods called NumIn() int and NumOut() int that give you the number of inputs/outputs.
However, keep in mind a few caveats:
To correctly extract the function for an arbitrary signature, you'll need an infinite number of cases. You'll have to switch over every single In and Out in turn to correctly get the type to extract.
You can't dynamically create a function anyway. There's no FuncOf method to go with SliceOf, MapOf, etc. You'll have to hand code the curried versions anyway.
Using reflection to emulate generics is generally considered a Bad Idea™.
If you absolutely have to do something like this, I'd heavily recommend making an interface and having each implementation do the currying itself, rather than trying to hack it "generically" for all cases, which will never work as of Go 1.2.1.

Go 1.5 will add a function that could help here.
(review 1996, commit e1c1fa2 by Dave (okdave))
// FuncOf returns the function type with the given argument and result types.
// For example if k represents int and e represents string,
// FuncOf([]Type{k}, []Type{e}, false) represents func(int) string.
//
// The variadic argument controls whether the function is variadic. FuncOf
// panics if the in[len(in)-1] does not represent a slice and variadic is
// true.
func FuncOf(in, out []Type, variadic bool) Type
The test cases include this intriguing code:
v := MakeFunc(FuncOf([]Type{TypeOf(K(""))}, []Type{TypeOf(V(0))}, false), fn)
outs := v.Call([]Value{ValueOf(K("gopher"))})

Related

Confusion with pointer, slices and interface{} in function arguments in go

I've been reading about how Go passes arguments to functions via pointer vs. value. I've been reading about the interface type. And I've been tampering with the reflect package. But clearly, I still don't understand how it all works because of this example code here:
package main
import (
"reflect"
"fmt"
)
type Business struct {
Name string
}
func DoSomething(b []Business) {
var i interface{}
i = &b
v := reflect.ValueOf(i).Elem()
for c:=0 ;c<10; c++ {
z := reflect.New(v.Type().Elem())
s := reflect.ValueOf(z.Interface()).Elem()
s.Field(0).SetString("Pizza Store "+ fmt.Sprintf("%v",c))
v.Set(reflect.Append(v, z.Elem()))
}
fmt.Println(b)
}
func main() {
business := []Business{}
DoSomething(business)
}
When I run this code, it will print a list of ten Business structs with the Business.Name of Pizza 0 to 9. I understand that in my example, that my DoSomething function received a copy of the slice of business, and hence, the business variable in my main function remains unaffected by whatever DoSomething does.
What I did next was change my func DoSomething(b []Business) to func DoSomething(b interface{}). Now when I try to run my script, I get the run time error of panic: reflect: Elem of invalid type on on the line z := reflect.New(v.Type().Elem())
I noticed that with DoSomething(b []Business), the variable i == &[]. But with DoSomething(b interface{}), the variable i == 0xc42000e1d0. Why is the variable i different under these two circumstances?
Your debugger most likely uses (or at least follows) the default formatting rules of the fmt package:
For compound objects, the elements are printed using these rules, recursively, laid out like this:
struct: {field0 field1 ...}
array, slice: [elem0 elem1 ...]
maps: map[key1:value1 key2:value2 ...]
pointer to above: &{}, &[], &map[]
In your first case i holds a value of type *[]Business. So if a value being printed (or inspected) is a pointer to slice, it is printed as &[values].
In your second case i holds a pointer to an interface{} value, which is of type *interface{}. When printing a value of this type, the default %p format is used which simply prints the memory address as a hexadecimal value prefixed with 0x.

Why is a map value in one function affected by an entry to the map in another function?

Here's my code:
func test(v map[string]string) {
v["foo"] = "bar"
}
func main() {
v := make(map[string]string)
test(v)
fmt.Printf("%v\n", v) // prints map[foo:bar]
}
I'm pretty new to Go, but as far as I was aware, since I'm passing the map value to test() and not a pointer to the map, the test() function should modify a different variable of the map, and thus, not affect the value of the variable in main(). I would have expected it to print map[]. I tested a different scenario:
type myStruct struct {
foo int
}
func test2(v myStruct) {
v.foo = 5
}
func main() {
v := myStruct{1}
test2(v)
fmt.Printf("%v\n", v) // prints {1}
}
In this scenario, the code behaves as I would expect. The v variable in the main() function is not affected by the changes to the variable in test2(). So why is map different?
You are right in that when you pass something to a function, a copy will be made. But maps are some kind of descriptors to an underlying data structure. So when you pass a map value to a function, only the descriptor will be copied which will denote / point to the same data structures where the map data (entries) are stored.
This means if the function does any modification to the entries of the map (add, delete, modify entries), that is observed from the caller.
Read The Go Blog: Go maps in action for details.
Note that the same applies to slices and channels too; generally speaking the types that you can create using the built-in make() function. That's why the zero value of these types is nil, because a value of these types need some extra initialization which is done when calling make().
In your other example you are using a struct value, they are not descriptors. When you pass a struct value to another function, that creates a complete copy of the struct value (copying values of all its fields), which –when modified inside the function– will not have any effect on the original, as the memory of the copy will be modified – which is distinct.

How to get the pointer of return value from function call?

I just need a pointer to time.Time, so the code below seems invalid:
./c.go:5: cannot take the address of time.Now()
I just wonder why? Is there any way to do that except to do assignment to a variable first and take the pointer of the variable?
package main
import "time"
func main() {
_ = &time.Now()
}
The probably unsatisfying answer is "you can't do it because the spec says so." The spec says that to use & on something it has to be addressable or a compound literal, and to be addressable it has to be "a variable, pointer indirection, or slice indexing operation; or a a field selector of an addressable struct operand; or an array indexing operation of an addressable array." Function calls and method calls are definitely not on the list.
Practically speaking, it's probably because the return value of a function may not have a usable address; it may be in a register (in which case it's definitely not addressable) or on the stack (in which case it has an address, but one that won't be valid if it's put in a pointer that escapes the current scope. To guarantee addressability, Go would have to do pretty much the exact equivalent of assigning it to a variable. But Go is the kind of language that figures that if it's going to allocate storage for a variable it's going to be because you said to, not because the compiler magically decided to. So it doesn't make the result of a function addressable.
Or I could be over-thinking it and they simply didn't want to have a special case for functions that return one value versus functions that return multiple :)
You can't directly take the address of a function call (or more precisely the return value(s) of the function) as described by hobbs.
There is another way but it is ugly:
p := &[]time.Time{time.Now()}[0]
fmt.Printf("%T %p\n%v", p, p, *p)
Output (Go Playground):
*time.Time 0x10438180
2009-11-10 23:00:00 +0000 UTC
What happens here is a struct is created with a literal, containing one element (the return value of time.Now()), the slice is indexed (0th element) and the address of the 0th element is taken.
So rather just use a local variable:
t := time.Now()
p := &t
Or a helper function:
func ptr(t time.Time) *time.Time {
return &t
}
p := ptr(time.Now())
Which can also be a one-liner anonymous function:
p := func() *time.Time { t := time.Now(); return &t }()
Or as an alternative:
p := func(t time.Time) *time.Time { return &t }(time.Now())
For even more alternatives, see:
How do I do a literal *int64 in Go?
Also see related question: How can I store reference to the result of an operation in Go?
Fortunately, generics now offer quite a clean solution by defining a function only one time, that can be used on any type:
package main
func ptr[T any](x T) *T {
return &x
}
func main() {
print(ptr("foo"))
print(ptr(42))
}
Playground: https://go.dev/play/p/TgpEPKjpXX7
However, this will work only starting from Golang 1.18. For previous versions, you'll need a function for each type, as other answers suggested.
If you are having this trouble with a function you wrote, change your function to return a pointer. Even though you can't take the address of a return value, you can dereference a return value, so it will be suitable whether you want the pointer or the object.
func Add(x, y int) *int {
tmp := x + y
return &tmp
}
func main() {
fmt.Println("I want the pointer: ", Add(3, 4))
fmt.Println("I want the object: ", *Add(3, 4))
}
https://play.golang.org/p/RogRZDNGdmY

How do I do a literal *int64 in Go?

I have a struct type with a *int64 field.
type SomeType struct {
SomeField *int64
}
At some point in my code, I want to declare a literal of this (say, when I know said value should be 0, or pointing to a 0, you know what I mean)
instance := SomeType{
SomeField: &0,
}
...except this doesn't work
./main.go:xx: cannot use &0 (type *int) as type *int64 in field value
So I try this
instance := SomeType{
SomeField: &int64(0),
}
...but this also doesn't work
./main.go:xx: cannot take the address of int64(0)
How do I do this? The only solution I can come up with is using a placeholder variable
var placeholder int64
placeholder = 0
instance := SomeType{
SomeField: &placeholder,
}
Note: the &0 syntax works fine when it's a *int instead of an *int64. Edit: no it does not. Sorry about this.
Edit:
Aparently there was too much ambiguity to my question. I'm looking for a way to literally state a *int64. This could be used inside a constructor, or to state literal struct values, or even as arguments to other functions. But helper functions or using a different type are not solutions I'm looking for.
The Go Language Specification (Address operators) does not allow to take the address of a numeric constant (not of an untyped nor of a typed constant).
The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x [in the expression of &x] may also be a (possibly parenthesized) composite literal.
For reasoning why this isn't allowed, see related question: Find address of constant in go. A similar question (similarly not allowed to take its address): How can I store reference to the result of an operation in Go?
0) Generic solution (from Go 1.18)
Generics are added in Go 1.18. This means we can create a single, generic Ptr() function that returns a pointer to whatever value we pass to it. Hopefully it'll get added to the standard library. Until then, you can use github.com/icza/gog, the gog.Ptr() function (disclosure: I'm the author).
This is how it can look like:
func Ptr[T any](v T) *T {
return &v
}
Testing it:
i := Ptr(2)
log.Printf("%T %v", i, *i)
s := Ptr("abc")
log.Printf("%T %v", s, *s)
x := Ptr[any](nil)
log.Printf("%T %v", x, *x)
Which will output (try it on the Go Playground):
2009/11/10 23:00:00 *int 2
2009/11/10 23:00:00 *string abc
2009/11/10 23:00:00 *interface {} <nil>
Your other options (prior to Go 1.18) (try all on the Go Playground):
1) With new()
You can simply use the builtin new() function to allocate a new zero-valued int64 and get its address:
instance := SomeType{
SomeField: new(int64),
}
But note that this can only be used to allocate and obtain a pointer to the zero value of any type.
2) With helper variable
Simplest and recommended for non-zero elements is to use a helper variable whose address can be taken:
helper := int64(2)
instance2 := SomeType{
SomeField: &helper,
}
3) With helper function
Note: Helper functions to acquire a pointer to a non-zero value are available in my github.com/icza/gox library, in the gox package, so you don't have to add these to all your projects where you need it.
Or if you need this many times, you can create a helper function which allocates and returns an *int64:
func create(x int64) *int64 {
return &x
}
And using it:
instance3 := SomeType{
SomeField: create(3),
}
Note that we actually didn't allocate anything, the Go compiler did that when we returned the address of the function argument. The Go compiler performs escape analysis, and allocates local variables on the heap (instead of the stack) if they may escape the function. For details, see Is returning a slice of a local array in a Go function safe?
4) With a one-liner anonymous function
instance4 := SomeType{
SomeField: func() *int64 { i := int64(4); return &i }(),
}
Or as a (shorter) alternative:
instance4 := SomeType{
SomeField: func(i int64) *int64 { return &i }(4),
}
5) With slice literal, indexing and taking address
If you would want *SomeField to be other than 0, then you need something addressable.
You can still do that, but that's ugly:
instance5 := SomeType{
SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField) // Prints 5
What happens here is an []int64 slice is created with a literal, having one element (5). And it is indexed (0th element) and the address of the 0th element is taken. In the background an array of [1]int64 will also be allocated and used as the backing array for the slice. So there is a lot of boilerplate here.
6) With a helper struct literal
Let's examine the exception to the addressability requirements:
As an exception to the addressability requirement, x [in the expression of &x] may also be a (possibly parenthesized) composite literal.
This means that taking the address of a composite literal, e.g. a struct literal is ok. If we do so, we will have the struct value allocated and a pointer obtained to it. But if so, another requirement will become available to us: "field selector of an addressable struct operand". So if the struct literal contains a field of type int64, we can also take the address of that field!
Let's see this option in action. We will use this wrapper struct type:
type intwrapper struct {
x int64
}
And now we can do:
instance6 := SomeType{
SomeField: &(&intwrapper{6}).x,
}
Note that this
&(&intwrapper{6}).x
means the following:
& ( (&intwrapper{6}).x )
But we can omit the "outer" parenthesis as the address operator & is applied to the result of the selector expression.
Also note that in the background the following will happen (this is also a valid syntax):
&(*(&intwrapper{6})).x
7) With helper anonymous struct literal
The principle is the same as with case #6, but we can also use an anonymous struct literal, so no helper/wrapper struct type definition needed:
instance7 := SomeType{
SomeField: &(&struct{ x int64 }{7}).x,
}
Use a function which return an address of an int64 variable to solve the problem.
In the below code we use function f which accepts an integer and
returns a pointer value which holds the address of the integer. By using this method we can easily solve the above problem.
type myStr struct {
url *int64
}
func main() {
f := func(s int64) *int64 {
return &s
}
myStr{
url: f(12345),
}
}
There is another elegant way to achieve this which doesn't produce much boilerplate code and doesn't look ugly in my opinion. In case I need a struct with pointers to primitives instead of values, to make sure that zero-valued struct members aren't used across the project, I will create a function with those primitives as arguments.
You can define a function which creates your struct and then pass primitives to this function and then use pointers to function arguments.
type Config struct {
Code *uint8
Name *string
}
func NewConfig(code uint8, name string) *Config {
return &Config{
Code: &code,
Name: &name,
}
}
func UseConfig() {
config := NewConfig(1, "test")
// ...
}
// in case there are many values, modern IDE will highlight argument names for you, so you don't have to remember
func UseConfig2() {
config := NewConfig(
1,
"test",
)
// ...
}
If you don't mind using third party libraries, there's the lo package which uses generics (go 1.18+) which has the .ToPtr() function
ptr := lo.ToPtr("hello world")
// *string{"hello world"}

Passing custom slice types by reference

I'm having trouble wrapping my head around how pointers, slices, and interfaces interact in Go. This is what I currently have coded up:
type Loader interface {
Load(string, string)
}
type Foo struct {
a, b string
}
type FooList []Foo
func (l FooList) Load(a, b string) {
l = append(l, Foo{a, b})
// l contains 1 Foo here
}
func Load(list Loader) {
list.Load("1", "2")
// list is still nil here
}
Given this setup, I then try to do the following:
var list FooList
Load(list)
fmt.Println(list)
However, list is always nil here. My FooList.Load function does add an element to the l slice, but that's as far as it gets. The list in Load continues to be nil. I think I should be able to just pass the reference to my slice around and have things append to it. I'm obviously missing something on how to get it to work though.
(Code in http://play.golang.org/p/uuRKjtxs9D)
If you intend your method to make changes, you probably want to use a pointer receiver.
// We also define a method Load on a FooList pointer receiver.
func (l *FooList) Load(a, b string) {
*l = append(*l, Foo{a, b})
}
This has a consequence, though, that a FooList value won't itself satisfy the Loader interface.
var list FooList
Load(list) // You should see a compiler error at this point.
A pointer to a FooList value, though, will satisfy the Loader interface.
var list FooList
Load(&list)
Complete code below:
package main
import "fmt"
/////////////////////////////
type Loader interface {
Load(string, string)
}
func Load(list Loader) {
list.Load("1", "2")
}
/////////////////////////////
type Foo struct {
a, b string
}
// We define a FooList to be a slice of Foo.
type FooList []Foo
// We also define a method Load on a FooList pointer receiver.
func (l *FooList) Load(a, b string) {
*l = append(*l, Foo{a, b})
}
// Given that we've defined the method with a pointer receiver, then a plain
// old FooList won't satisfy the Loader interface... but a FooList pointer will.
func main() {
var list FooList
Load(&list)
fmt.Println(list)
}
I'm going to simplify the problem so it's easier to understand. What is being done there is very similar to this, which also does not work (you can run it here):
type myInt int
func (a myInt) increment() { a = a + 1 }
func increment(b myInt) { b.increment() }
func main() {
var c myInt = 42
increment(c)
fmt.Println(c) // => 42
}
The reason why this does not work is because Go passes parameters by value, as the documentation describes:
In a function call, the function value and arguments are evaluated in the usual
order. After they are evaluated, the parameters of the call are passed by value
to the function and the called function begins execution.
In practice, this means that each of a, b, and c in the example above are pointing to different int variables, with a and b being copies of the initial c value.
To fix it, we must use pointers so that we can refer to the same area of memory (runnable here):
type myInt int
func (a *myInt) increment() { *a = *a + 1 }
func increment(b *myInt) { b.increment() }
func main() {
var c myInt = 42
increment(&c)
fmt.Println(c) // => 43
}
Now a and b are both pointers that contain the address of variable c, allowing their respective logic to change the original value. Note that the documented behavior still holds here: a and b are still copies of the original value, but the original value provided as a parameter to the increment function is the address of c.
The case for slices is no different than this. They are references, but the reference itself is provided as a parameter by value, so if you change the reference, the call site will not observe the change since they are different variables.
There's also a different way to make it work, though: implementing an API that resembles that of the standard append function. Again using the simpler example, we might implement increment without mutating the original value, and without using a pointer, by returning the changed value instead:
func increment(i int) int { return i+1 }
You can see that technique used in a number of places in the standard library, such as the strconv.AppendInt function.
It's worth keeping a mental model of how Go's data structures are implemented. That usually makes it easier to reason about behaviour like this.
http://research.swtch.com/godata is a good introduction to the high-level view.
Go is pass-by-value. This is true for both parameters and receivers. If you need to assign to the slice value, you need to use a pointer.
Then I read somewhere that you shouldn't pass pointers to slices since
they are already references
This is not entirely true, and is missing part of the story.
When we say something is a "reference type", including a map type, a channel type, etc., we mean that it is actually a pointer to an internal data structure. For example, you can think of a map type as basically defined as:
// pseudocode
type map *SomeInternalMapStructure
So to modify the "contents" of the associative array, you don't need to assign to a map variable; you can pass a map variable by value and that function can change the contents of the associative array pointed to by the map variable, and it will be visible to the caller. This makes sense when you realize it's a pointer to some internal data structure. You would only assign to a map variable if you want to change which internal associative array you want it to point to.
However, a slice is more complicated. It is a pointer (to an internal array), plus the length and capacity, two integers. So basically, you can think of it as:
// pseudocode
type slice struct {
underlyingArray uintptr
length int
capacity int
}
So it's not "just" a pointer. It is a pointer with respect to the underlying array. But the length and capacity are "value" parts of the slice type.
So if you just need to change an element of the slice, then yes, it acts like a reference type, in that you can pass the slice by value and have the function change an element and it's visible to the caller.
However, when you append() (which is what you're doing in the question), it's different. First, appending affects the length of the slice, and length is one of the direct parts of the slice, not behind a pointer. Second, appending may produce a different underlying array (if the capacity of the original underlying array is not enough, it allocates a new one); thus the array pointer part of the slice might also be changed. Thus it is necessary to change the slice value. (This is why append() returns something.) In this sense, it cannot be regarded as a reference type, because we are not just "changing what it points to"; we are changing the slice directly.

Resources