While developing GoDerive, a code generator for Go, I ran into the following problem.
I could not infer the type of the input arguments of a function, if that function's input argument types are not specified and the function is not being called right away.
I wanted to write:
func TestCurriedEqualCompileError(t *testing.T) {
curriedEqual := deriveCurry(deriveEqual)
if !curriedEqual(&User{})(&User{}) {
t.Fatalf("not equal")
}
}
, where functions that start with the prefix "derive" are generated.
This can be fixed by rewriting it as:
func TestCurriedEqualCompileError(t *testing.T) {
curriedEqual := deriveCurry(func(a, b *User) bool {
return deriveEqual(a, b)
})
if !curriedEqual(&User{})(&User{}) {
t.Fatalf("not equal")
}
}
, but this is not ideal.
I tried to find how Go does this for it's generic functions, like copy
,
but I found that this limitation is actually part of the Go specification:
The built-in functions do not have standard Go types, so they can only appear in call expressions; they cannot be used as function values.
https://golang.org/ref/spec#Built-in_functions
Here is an example to showcase the limitation:
func twoslice(a, b []int, f func(c, d []int) int) {
f(a, b)
}
func main() {
a, b := []int{1,2}, []int{3, 4}
twoslice(a, b, copy)
fmt.Println("%v, %v", a, b)
}
https://play.golang.org/p/ghITepOq6l
This gives the following error:
use of builtin copy not in function call
I am not saying this is an easy problem to solve, but it stops GoDerive from generating functions that can be passed as values.
In the meantime I have updated my code generator's deriveEqual function to be able to generate, given only the first argument.
This allows us to now write:
func TestCurriedEqualCompileError(t *testing.T) {
if !deriveEqual(&User{})(&User{}) {
t.Fatalf("not equal")
}
}
, but this will not be possible for all such usecases.
This is just my experience of trying to generate generic functions in Go and one of the limitations I ran into.