DEV Community

Mark Karamyar
Mark Karamyar

Posted on • Originally published at devmarkpro.com on

Generic in Golang

This year started with new news from the golang team, "Adding Generic!".

If you have familiar with languages like Java or C#, you already familiar with the concept of Generics. For example, let's talk about sorting an array.

package main

import (
    "fmt"
    "sort"
)

func main() {
    f := func(msg string, v []int) {
        fmt.Println(msg)
        for _, x := range v {
            fmt.Printf("%d ", x)
        }
        fmt.Println()
    }
    v := []int{10, 20, 100, 2, -1, 80}
    f("before sort", v)
    sort.Ints(v)
    f("after sort", v)
}

Enter fullscreen mode Exit fullscreen mode

In the above code, we just used the sort package to sorting a slice of integers and print them out.

Everything looks good, right? So what if we wanted to sort a slice of other numeric types? The sort package has another function called Float64s (instead of Ints) but it's definitely not enough because we might need to do some sorting operation on other numeric types like int32.

So one approach is to define one function for each numeric type but we all know it's not the best idea! it's the place that Generic comes to picture.

Here's the definition of Generic in Wikipedia :

Generic programming is a style of computer programming in which algorithms are written in terms of types to-be-specified-later that are then instantiated when needed for specific types provided as parameters.

So the point of generic is, specify the type of the variable later and provide it as a parameter. That's exactly what we need for example in our sort function. The only thing that we need is to make sure our input comply our conditions. for example in the sorting scenario, it must be numeric.

Let's see how we can use generic in golang:

func Bored[T any](s ...T) T {
    return s[0]
}

Enter fullscreen mode Exit fullscreen mode

Bored function gives a slice of T as input and returns the first item in the slice as output. So WTH is T? first thing first, let's see how to use our Bored function:

func main() {
    output := Bored("Hello", "Generics")
    fmt.Println(output)
}

Enter fullscreen mode Exit fullscreen mode

That's great, a generic function is used exactly like a normal function! so let's talk about T: In this case, T is string. so what's the difference between generic and the old-fashioned go interface{}? I'll explain it with an example.

func Bored(s ...interface{}) interface{} {
    return "I am string"
}
func main() {
    output := Bored(1,1.1,"hello", struct{}{})
    fmt.Println(output)
}

Enter fullscreen mode Exit fullscreen mode

The difference is, interface{} could be anything but in the first function the type of T determined while passing the first element to it. if it's a string, the rest of them also must be a string. otherwise, you'll get an error while compiling the application.


func Bored[T any](s ...T) T {
    return s[0]
}

func main() {
    output := Bored("Hello", "Generics", 1)
    fmt.Println(output)
}

Enter fullscreen mode Exit fullscreen mode

output:

type checking failed for main
prog.go2:11:39: default type int of 1 does not match inferred type string for T

Enter fullscreen mode Exit fullscreen mode

It's nice, isn't it? for Java or C# developers something like Repository<T> is pretty familiar which T is almost always one of the application's entities.

Back to Golang, the other type (instead of any) that introduced now, is comparable. It means the item must have the capability of being in equality operation.

package main

import (
    "fmt"
)

func main() {
    fmt.Println(Equal(1, 1)) // true
    fmt.Println(Equal(2, 1)) // false
}

func Equal[T comparable] (input1, input2 T) bool {
    return input1 == input2
}

Enter fullscreen mode Exit fullscreen mode

and same previous example we got a compile-time if pass multiple data type to this function:

func main() {
    fmt.Println(Equal(1.1, 1))
}
/*
output: type checking failed for main
prog.go2:8:25: default type int of 1 does not match inferred type float64 for T
*/

Enter fullscreen mode Exit fullscreen mode

I think the golang team provides some ways for developers to define the restriction of the type T themselves. for now, I just have seen any and comparable, if you know more typed parameter please share them in the comment section;

Top comments (1)

Collapse
 
ibukuntech profile image
Oyetunji Ibukunoluwa Oluwole

This is good