Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go Experience Report: Generic functions cannot be passed as values #10

Open
awalterschulze opened this issue Jul 2, 2017 · 0 comments

Comments

@awalterschulze
Copy link
Owner

awalterschulze commented Jul 2, 2017

Generic functions cannot be passed as values

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.

@awalterschulze awalterschulze changed the title derive higher order functions with input functions that should also be derived. Go Experience Report: Generic functions cannot be passed as values Sep 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant