Skip to content

Instantly share code, notes, and snippets.

@danicat
Last active August 29, 2018 15:51
Show Gist options
  • Save danicat/26b05c28b2d7f59f18d6382405d3c62b to your computer and use it in GitHub Desktop.
Save danicat/26b05c28b2d7f59f18d6382405d3c62b to your computer and use it in GitHub Desktop.
Golang Generics Exploration
package main
import (
"fmt"
)
func main() {
// One strategy is to include type info as the first 'n' parameters
fmt.Println(genericAdd("int", 1, 2))
fmt.Println(genericAdd("string", "1", "2"))
// But if you want a typed return you need to specialize the functions
intAdd := func(a, b int) int {
return genericAdd("int", a, b).(int)
}
strAdd := func(a, b string) string {
return genericAdd("string", a, b).(string)
}
fmt.Println(intAdd(1, 2))
fmt.Println(strAdd("1", 2)) // type safety: don't compile!
// The syntax with genericAdd2 looks cleaner, but has some faults:
intAdd2 := genericAdd2("int")(1, 2)
strAdd2 := genericAdd2("string")("1", 2) // you won't get this error at compile time = panic!
fmt.Printf("%#v with type %T\n", intAdd2, intAdd2)
fmt.Printf("%#v with type %T\n", strAdd2, strAdd2)
}
type Any interface{}
// Type T should be a real type instead of a string. Since we are returning a generic value
// we need an additional stage to make the type explicit again, hence the wrapper functions
// above.
func genericAdd(T string, a, b Any) Any {
if T == "string" {
return a.(string) + b.(string)
}
if T == "int" {
return a.(int) + b.(int)
}
panic("unsuported type")
}
// Ideally we would be able to return a specialized function instead of a generic one
// in order to increase type safety at compile time. But the usage of this version is
// cleaner than the first one.
func genericAdd2(T string) func(a, b Any) Any {
if T == "string" {
// Current spec doesn't allow returning func(a, b string) string
return func(a, b Any) Any {
return a.(string) + b.(string)
}
}
if T == "int" {
// Current spec doesn't allow returning func(a, b int) int
return func(a, b Any) Any {
return a.(int) + b.(int)
}
}
panic("unsuported type")
}
// How true generics would look like:
// func fakeGenericAdd(type T)(a, b T) T {
// return a + b // panics if + is not implemented for type T
// }
// someInt := fakeGenericAdd(int)(1,2)
// someStr := fakeGenericAdd(string)("1",2)
@danicat
Copy link
Author

danicat commented Aug 29, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment