My recent involvement with my new side project, go-linq, showed me that type system of Go is not designed for anything near object-oriented programming. There are no generics, no type inheritance, or anything helpful for certain purposes.

However there is a type called interface{} you can assign pretty much anything into it, like object in .NET or Object in Java:

var o interface{}
o := 3.14
o := Student{Name:"Ahmet"}

and it does not give any compilation errors. So let’s say you need a function that accepts slices of any type. If you are thinking to do something like:

func Method(in []interface{}){...}
...
slice := []int{1,2,3}
Method(slice) // gives error

That gives a compilation error, because []int is not an []interface{}. So what’s the solution here? You can require users of Method to convert their slices to []interface{}. Now they have to convert their []AnyType to []interface{} with the help of a function like:

func conv(in []AnyType) (out []interface{}) {
    out = make([]interface{}, len(in))
    for i, v := range in {
        out[i] = v
    }
    return
}

But that does not scale. If your user of Method (and this can be a common function like Map, Filter etc.) has N different types they would like to pass to Method, they have to write N conv methods.

What can we do here? Of course, reflection. We will take input as interface{} (which can be of any value) and we will convert it to a slice internally and use it in our Method. How to do that:

func takeSliceArg(arg interface{}) (out []interface{}, ok bool) {
    slice, success := takeArg(arg, reflect.Slice)
    if !success {
        ok = false
          return
    }
    c := slice.Len()
    out = make([]interface{}, c)
    for i := 0; i < c; i++ {
        out[i] = slice.Index(i).Interface()
    }
    return out, true
}

func takeArg(arg interface{}, kind reflect.Kind) (val reflect.Value, ok bool) {
    val = reflect.ValueOf(arg)
    if val.Kind() == kind {
        ok = true
    }
    return
}

takeArg() function tries to convert value to the specified reflect.Kind and takeSliceArg() function tries to convert a value passed to itself to a slice of interface{}. Although, there’s just a little bit of performance drawback caused by reflection, it is not much.

That’s it. This approach is inspired by Tobia Confronto’s fn project and integrated to go-linq.

This post is written while drunk I don’t take any responsibility about it.