Generics in Golang

In the article we will take the advantage of [generics] even that they are not
first citizen in Go. We will explore gen and
genny command line tools.

Gen

Gen is a code generation tool that brings some generic query functions. It uses
annotations to add this functionality to any structure. The generated code is
part of your package and does not have any external dependencies. This approach
avoids any reflection and produces an efficient concrete implementation for any
annotated type.

By default the package generates various query functions. They can be used to
project, filter, sort and group slices of the annotated types.

Installation

We should use go get command to install gen:

$ go get clipperhouse.github.io/gen

Usage

As any other Go generation tool, Gen requires a specific annoation comment
declared before the desired type declaration.

// +gen [*] tag:"Value, Value[T,T]" anothertag
type AnnotatedType

It begins with the +gen directive. Optionally it is followed by a [*],
indicating that the generated type should be a pointer. Tags and values are
interpreted by the available type writers. They are responsible for the actual
code generation. We will learn more about them in the next section. For now we
will use the default slice type writer.

Lets use it to generate functions for filtering, distincting, sorting and projecting
a Company struct:

If we want to sort the companies by their name, we should use SortBy function
that receives as an argument a function that determines whether its first argument
is less that second one:

// In our case we can use strings.Compare to compare to strings. It returns -1
// the first string is less than the second.
sortedCompanies := companies.SortBy(func(compA company.Company, compB company.Company) bool {
return strings.Compare(compA.Name, compB.Name) == -1
})

If we want to group the companies by their country of residence, we can use
GroupByString function that returns a map[string]company.CompanySlice object.
The key of every entry is determined by its clojure function.