I don't know if anyone cares about another attempt to brute-force generics 
into Go 1, but I've written up a proof of concept here:
http://kothar.net/generic-adapters

This uses structs with func fields to emulate methods, and then generates 
adapters at runtime between the typed functions and the generic methods:

type Container struct {
 T SomeType

 Set func(value SomeType) SomeType
}


type Int64Container struct {
 T int64

 Set func(value int64) int64
}


func myProgram() {
 c := &Int64Container{}
 generic.Factory(Container{}).Create(c)
}

My intent was to make generics work in the same spirit to interfaces, and 
allow any generic implementation using interface{} to be cast to a more 
specialised interface with concrete types.



Regardless of whether this is a bad idea or not, one question I ran into is 
about how slow the reflective wrappers are compared to optimised 
compile-time code.

I know it's common knowledge that reflection is slow, so this isn't a 
surprise in general. However, even when the function call signature and 
method signature match (apart from the receiver) assigning the 
reflect.Method to the func field value adds quite a large overhead compared 
to the equivalent compile-time code (60x).

See 
https://bitbucket.org/mikehouston/generic/src/0e86e6eccdc9e84b9cfb7b0322c98964d21b0f4e/test/list/list_test.go?at=master&fileviewer=file-view-default#list_test.go-194

func BenchmarkFuncListSet(b *testing.B) {
        l := &Int32ListImpl{}
        l.Append(1)

        list := &Wrapper{}
        list.Set = l.Set

        b.ResetTimer()
        for i := 0; i < b.N; i++ {
                list.Set(0, 5)
        }
}

func BenchmarkReflectFuncListSet(b *testing.B) {
        impl := &Int32ListImpl{}
        impl.Append(1)

        list := &Wrapper{}
        listValue := reflect.Indirect(reflect.ValueOf(list))
        implValue := reflect.ValueOf(impl)
        method := implValue.MethodByName("Set")
        listValue.FieldByName("Set").Set(method)

        b.ResetTimer()
        for i := 0; i < b.N; i++ {
                list.Set(0, 5)
        }
}



BenchmarkDirectListSet-8                2000000000               0.53 ns/op
BenchmarkInterfaceListSet-8             500000000                2.98 ns/op
BenchmarkFuncListSet-8                  500000000                3.04 ns/op
BenchmarkReflectFuncListSet-8           10000000               185 ns/op


I presume this is because the compiler can generate a much more efficient 
inline wrapper function without any additional type checks, while the 
reflected method is similar to reflect.MakeFunc in behaviour, and needs to 
check the types of all arguments during each invocation.

Any thoughts on how to reduce some of the overhead would be welcome, but 
I'm prepared to accept that this is just the cost of making these wrappers 
at runtime with the current reflection support.

Mike.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to