trying to use interface{} to a slice to select random element - go

I've been trying to implement a function which can randomly select an element from any type of slice (like python's random.choice function)
func RandomChoice(a []interface{}, r *rand.Rand) interface{} {
i := r.Int()%len(a)
return a[i]
}
However, when I try to pass in a slice of type []float32 into the first argument this error occurs:
cannot use my_array (type []float32) as type []interface {} in function argument
is this a fundemental misuse of interface{}? is there some better way to do this?

Re: is there some better way to do this?
IMO there is. The OP approach is inefficient wrt to simple:
var v []T
...
// Select a random element of 'v'
e := v[r.Intn(len(v))]
...
Note that both of the approaches will panic for len(v) == 0 until a pre-check for this is made.

Using reflection:
func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
x := reflect.ValueOf(slice)
return x.Index(r.Intn(x.Len())).Interface()
}

From the language specification:
Two types are either identical or different.
Two named types are identical if their type names originate in the
same TypeSpec. A named and an unnamed type are always different. Two
unnamed types are identical if the corresponding type literals are
identical, that is, if they have the same literal structure and
corresponding components have identical types. In detail:
Two array types are identical if they have identical element types and
the same array length.
Two slice types are identical if they have
identical element types.
Two struct types are identical if they have the same sequence of fields, and if corresponding fields have the same names, and identical
types, and identical tags. Two anonymous fields are considered to have
the same name. Lower-case field names from different packages are
always different.
Two pointer types are identical if they have identical base types.
Two function types are identical if they have the same number of parameters and result values, corresponding parameter and result types
are identical, and either both functions are variadic or neither is.
Parameter and result names are not required to match.
Two interface types are identical if they have the same set of methods with the same names and identical function types. Lower-case
method names from different packages are always different. The order
of the methods is irrelevant.
Two map types are identical if they have identical key and value types.
Two channel types are identical if they have identical value types and the same direction.
And:
A value x is assignable to a variable of type T ("x is assignable to
T") in any of these cases:
x's type is identical to T.
x's type V and T have identical underlying types and at least one of V or T is not a named type.
T is an interface type and x implements T.
x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not
a named type.
x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
x is an untyped constant representable by a value of type T.
Any value may be assigned to the blank identifier.
The combination of these two results that you can't assign a []MyType to an []interface{}.

Well, I can hardly believe after all the searching, that the first listed related question was: Type converting slices of interfaces in go which pretty much contains the answer.
Changing RandomChoice to use the InterfaceSlice function described in the answer to that question yields:
func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
islice := InterfaceSlice(slice)
i := r.Int()%len(islice)
return islice[i]
}
although apparently this answer is not very well performing, because it requires the entire slice to be converted to []interface{}...

Related

How to write a Go type constraint for something you can take len() of?

I am trying to write a type constraint for a Go program, that accepts "anything you can take len() of". But I can't really figure it out.
I want something like:
LenOf[m Measurable](m M) int {
return len(m)
}
I tried a few things. Fx. this naiive thing, which do compile, but doesn't work on all types (like fx []User):
type Measurable interface {
~string | []any | ~map[any]any
}
Then went on to something like, the below which not only makes the function signature for LenOf() extremely clunky, but also have clumsy to write on call sites (and still can't get it to compile)
type Measurable[K comparable, V any] interface {
~string | []V | ~map[K]V
}
Why? The builtin len is already "generic".
With that said, let's see why defining such a constraint is a bad idea. The Go spec has a paragraph — Length and capacity, that can help:
If the argument type is a type parameter P, the call len(e) (or cap(e) respectively) must be valid for each type in P's type set. The result is the length (or capacity, respectively) of the argument whose type corresponds to the type argument with which P was instantiated.
The issues with writing an all-encompassing constraint for "measurable" types are:
it includes arrays [N]T, where the array length is part of the type, so your constraint would have to specify all possible arrays you want to capture
it includes array pointers *[N]T, which you can't easily abstract in a type constraint
it includes maps, which forces you to capture keys K and values V, which may or may not be the same as T. Plus, K must implement comparable.
So you'd have to write something like:
type Measurable[T any, K comparable, V any] interface {
~string | ~[]T | ~map[K]V | ~chan T
}
which notably doesn't include arrays, and doesn't distinctly capture pointer literals, e.g. to match []*int, you would have to instantiate T with *int.
You might simplify V away:
type Measurable[T any, K comparable] interface {
~string | ~[]T | ~map[K]T | ~chan T
}
The function LenOf then becomes:
func LenOf[T any, K comparable, M Measurable[T, K]](m M) int {
return len(m)
}
but you still have to supply K, so you have to instantiate LenOf at call site with bogus types for the map key:
LenOf[string, int]("foo")
// ^ actually useless
and you can't take advantage of type inference with the argument either.
In conclusion: just use len. Design your generic functions to work with type literals that support length, or add to the constraint only those types that your functions are reasonably expected to handle.

What is the difference between comparable and any?

I have tried to use generics with Go, but I don't really understand when we use any or comparable as type parameter. Can someone help to understand these?
It depends on what / how you want to use values of the parameter type. Constraints restrict what you can do with values of those types.
any is an alias for interface{} which allows any type. If a parameter can be of any type, that basically won't allow you to do anything with it because you have no guarantee what it will be.
The comparable constraints only allows types that are comparable, that is, the == and != operators are allowed to use on values of them. This is good if you want to use the type as a key in a map (maps require key types to be comparable), or if you you want to find an element in a slice, and you want to use the == operator to compare the elements to something.
As an example, let's write a generic map-get function:
func get[K comparable, V any](m map[K]V, key K) V {
return m[key]
}
The K key type must be comparable, else it cannot be used as the key type of some map (m[K]V in the example). V on the other hand shouldn't be constrained, the value type may be anything, and we're not doing anything with it (just returning a value of type V), so using any here is the best choice.
Another example, a slice-find function:
func find[V comparable](what V, s []V) int {
for i, v := range s {
if v == what {
return i
}
}
return -1
}
find() returns the index of the first occurrence of what in the slice s, and if it's not in the slice, returns -1. The type parameter V here must be comparable, else you couldn't write v == what, using V any would be a compile-time error. The constraint comparable ensures this find() function can only be instantiated with types (and called with values) where the == operator is defined and allowed.
The difference between comparable and any will change with Go 1.20 (Q1 2023) and (accepted) the proposal "56548: spec: allow basic interface types to instantiate comparable type parameters".
any will implement the comparable constraint (which it does not before Go 1.20).
Go 1.20-rc1 states:
Comparable types (such as ordinary interfaces) may now satisfy comparable constraints, even if the type arguments are not strictly comparable (comparison may panic at runtime).
This makes it possible to instantiate a type parameter constrained by comparable (e.g., a type parameter for a user-defined generic map key) with a non-strictly comparable type argument such as an interface type, or a composite type containing an interface type.
The principle is:
After substitution, each type argument must satisfy the constraint (instantiated, if necessary) of the corresponding type parameter. Otherwise instantiation fails.
With "satisfy" being:
A type T satisfies a constraint interface C if
T implements C; or
C can be written in the form interface{ comparable; E }, where E is a basic interface and T is comparable and implements E.
Example:
Currently, any does not implement the comparable constraint.
With the proposed change any will be permitted as type argument for comparable: comparable can be written as interface{ comparable; E } and thus the new rule applies, and any is spec-comparable and implements E (where E is the empty interface in this case).
Currently, the type parameter P in the type parameter list
[P interface{ comparable; fmt.Stringer }]
cannot be instantiated with the type S
type S struct {
data any
}
func (S) String() string
because S is not strictly comparable.
With the proposed change, S must only be spec-comparable (which it is) and implement fmt.Stringer (which it does).
("spec-comparable" are for types of comparable operands)
(as opposed to "strictly comparable", which is for the types in comparable, namely the set of (non-interface) types for which == and != are defined and for which these operations are guaranteed to not panic)
The implementation as started:
CL 453979: "cmd/compile: enable new comparable semantics by default"
CL 453978: "go/types, types2: make the new comparable semantics the default"

How is the itab struct actually having a list of function pointers?

Researching the interface value in go - I found a great (maybe outdated) article by Russ Cox.
According to it:
The itable begins with some metadata about the types involved and then becomes a list of function pointers.
The implementation for this itable should be the one from src/runtime/runtime2.go:
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
First confusing thing is - how is an array - variable sized?
Second, assuming that we have a function pointer at index 0 for a method that satisfies the interface, where could we store a second/third/... function pointer?
The compiled code and runtime access fun as if the field is declared fun [n]uintpr where n is the number of methods in the interface. The second method is stored at fun[1], the third at fun[2] and so on. The Go Language does not have a variable size array feature like this, but unsafe shenanigans can be used to simulate the feature.
Here's how itab is allocated:
m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*goarch.PtrSize, 0, &memstats.other_sys))
The function persistentalloc allocates memory. The first argument to the function is the size to allocate. The expression inter.mhdr is the number of methods in the interface.
Here's code that creates a slice on the variable size array:
methods := (*[1 << 16]unsafe.Pointer)(unsafe.Pointer(&m.fun[0]))[:ni:ni]
The expression methods[i] refers to the same element as m.fun[i] in a hypothetical world where m.fun is a variable size array with length > i. Later code uses normal slice syntax with methods to access the variable size array m.fun.

How are two interfaces matched in golang

How are interface{} values compared if I have a type of map[interface{}]interface{} and I have another map which has map[string]interface{}.
How are the hashes evaluated if I have a
m := make(map[string]interface{}) and I execute m[m["key"]] i.e. I am passing an interface{} value for a map with string as key.
And vice versa case, that is :
m1 := make(map[interface{}]interface{}) and I execute m1[m["key"]]
Go interfaces are a 2 word value, and are compared as such. From the Language Specification section on Comparison Operators:
Interface values are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil.
A value x of non-interface type X and a value t of interface type T are comparable when values of type X are comparable and X implements T. They are equal if t's dynamic type is identical to X and t's dynamic value is equal to x.
Only the first point is relevant in the case of the map[interface{}]T, since the key is always converted to an interface{} for comparison.

mixing "exploded" slices and regular parameters in variadic functions

I'm wondering why it's not possible to do the following in go:
func main() {
stuff := []string{"baz", "bla"}
foo("bar", stuff...)
}
func foo(s ...string) {
fmt.Println(s)
}
In my understanding, slice... "explodes" the slice so it can be used for multi argument function calls. So the above example should actually expand to foo("bar", "baz", "bla").
foo(stuff...) works as expected, no surprises here, but in the example above, the compiler complains about too many arguments.
Is this a desired limitation? I'm coming from a ruby background where a foo("bar", *stuff) is perfectly fine (and is, at least in my book, the same thing), that's why this surprises me.
The value for a variadic argument can be specified either by enumerating the elements, or using an existing slice, specified by its name followed by ....
You want to mix the 2 possible ways which is not permitted by the Go Language Specification (Passing arguments to ... parameters).
If the first form is used (enumerating the elements):
The value passed [as the variadic parameter] is a new slice of type []T with a new underlying array whose successive elements are the actual arguments.
If the latter is used (passing an existing slice followed by ...) no new slice is created, the one you pass is used as is. And the passed slice can only be used to specify the value of one – the final – variadic parameter. Attempting to pass both a single element and a slice will not match the signature (the parameter list in this case) of your function and you'll get an error:
too many arguments in call to foo
There is no actual "exploding" involved in Go, the term is just used in other languages to help visualize that the passed array or slice will not be an element of the variadic parameter but will be the value of variadic parameter itself.
Mixing the 2 would require to allocate a new slice because obviously the existing slice cannot be used.
The ugly way to get this to work is make it into a new variadic.
foo(append([]string{"bar"}, stuff...)...)
And if the order doesn't matter:
foo(append(stuff, "bar")...)
https://play.golang.org/p/mY6y0vScfPB
The specification on this is at the "Passing arguments to ... parameters":
If f is variadic with a final parameter p of type ...T, then within f the type of p is equivalent to type []T.
If f is invoked with no actual arguments for p, the value passed to p is nil.
Otherwise, the value passed is a new slice of type []T with a new underlying array whose successive elements are the actual arguments, which all must be assignable to T.
In your case, where stuff... works:
If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.
But "bar", stuff... doesn't match either case specified above.
T, []T doesn't match f([]T).
I ran into this situation when preparing arguments to feed to external commands. If possible, just build an one argument slice, then you don't have to worry about combining scalars with slices when it's time to call the function:
package main
import "os/exec"
func main() {
stuff := []string{"bar"}
stuff = append(stuff, "baz", "bla")
exec.Command("name", stuff...).Run()
}

Resources