Credit by Golang Official Blog
In many programming languages such as Java,
Kotlin,
Objective-C,
and Swift,
they support the Generic programming. But in Golang, it doesn’t have that kind of feature. What if we want to use this feature, how can we do? Let’s check the Interface
in Golang. And how it can achieve the generic programming in Golang.
Let’s see the definition of Generic Programming
from Wikipedia:
Generic programming is defined in Musser & Stepanov (1989) as follows, Generic programming centers around the idea of abstracting from concrete, efficient algorithms to obtain generic algorithms that can be combined with different data representations to produce a wide variety of useful software.
— Musser, David R.; Stepanov, Alexander A., Generic Programming[5]
The original idea describes that we design an algorithm to solve a problem, but we don’t care about the types of objects involved. We use a sorting algorithm to sort fruits from small sizes to large sizes. This algorithm should be able to apply on apples, oranges, guavas, and other different kinds of fruits. We don’t care about what kind of fruit is, we only focus on the size
issue.
How other languages do generic programming?
Java
1 | public class GenericFoo<T> { |
Kotlin
1 | class GenericFoo<T>() { |
Objective-C
1 | @interface GenericFoo<ObjectType> : NSObject |
Swift
1 | struct GenericFoo<T> { |
What about Golang? Can Golang do the same thing as other programming languages do? Unfortunately, Golang doesn’t support generic programming
because it does not have that syntax to do. That’s its drawback, but we still have another way to do a similar thing. The answer is Interface.
What’s Interface
in Golang? Let’s see an example:
1 | type geometry interface { |
So, we define an interface - geometry with two methods:
- area() // get the geometry area.
- perim() // get the perimeter of this geometry.
And a measure function that accepts a geometry
interface type. How do we use that? You can create two different geometry objects.
1 | type rect struct { |
A tip here, when you implement all methods in an interface, then you are a type of that interface, which is so-called Duck typing the core concept of Golang Interface.
1 | // duck typing |
That means these two objects are well-defined geometries. We can use both of them in measure function.
1 | func main() { |
Through the interface design, we can easily do the generic programming on Go. What’s another benefit to using the interface? The most significant benefit is that you can hide your implementation detail. Let’s check Sort.go
source code:
1 | // A type, typically a collection, that satisfies sort.Interface can be |
It defines three methods, Len()
, Less() bool
, Swap()
. When you try to use Sort interface. Just do something like this:
1 | // Insertion sort |
You pass a data as an Interface; then we don’t need to care about what the real type of data is, we need to know: we can use the data to do Swap. Another interesting thing I want to mention is that the interface allows you to hook/intercept with a customized handler created by you to assemble with other data, which is so-called dynamic dispatch. Let’s see an example:
If you try to use http.Get
to get some resources from server-side:
1 | func main() { |
What if we need to add an authentication token to the header for a request? You might try to use http client to do something like this:
1 | type header struct { |
The header implements the RoundTripper interface that only contains one method - RoundTrip. This interface gives us a chance to put authorization token into every request without manually add it into request header. That’s powerful.
The interface is a foundational feature in Golang, but some benefits build on the runtime that means performance cost. So we should use them carefully.
Happy coding. Enjoy!