If Go's interfaces aren't enforced, are they necessary?

The Go language has interface types as features, analogous to C-style interfaces. Go's interface types, though, don't seem to be enforced -- they merely define protocol without actually being applied to a type. As they are not enforced, is it still a good idea to use interfaces?


Solution 1:

Yes. Go doesn't allow you to build type-hierarchies, so interfaces are very important to allow some polymorphism. Consider the sort.Interface defined in the package sort:

type Interface interface {
    // Len is the number of elements in the collection.
    Len() int
    // Less returns whether the element with index i should sort
    // before the element with index j.
    Less(i, j int) bool
    // Swap swaps the elements with indexes i and j.
    Swap(i, j int)
}

The sort package contains a function sort(data Interface) that expects any object that implements this interface. Without interfaces, such form of polymorphism would not be possible in go. The fact that you don't have to explicitly annotate that your type implements this interface, is irrelevant.

The cool part about go is that you can even implement this interface on primitive types, as long as the type is defined in the same package. So the following code defines a sortable array of integers:

type Sequence []int

// Methods required by sort.Interface.
func (s Sequence) Len() int {
    return len(s)
}
func (s Sequence) Less(i, j int) bool {
    return s[i] < s[j]
}
func (s Sequence) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}

Solution 2:

Yes, it is still an excellent idea to use interfaces. Go emphases interfaces. See https://talks.golang.org/2014/go4gophers.slide#5. Extending @ElianEbbing outstanding answer, methods on any types and ad hoc interfaces make for a light-weight OO programming style. See https://talks.golang.org/2012/goforc.slide#48.

An example might illustrate this.

package main

import . "fmt"

func main() {
    c.Cry()      // Meow
    Cryer.Eat(c) // Fish
}

var c = cat{"Fish"}
type cat struct{ s string }
type Eater interface{ Eat() }
type Cryer interface {
    Cry()
    Eater
}
func (c cat) Eat() { Println(c.s) }
func (cat) Cry()   { Println("Meow") }

The Cryer interface lets you access both the Cry() and Eat() methods. See https://talks.golang.org/2012/zen.slide#16. You can add Cryer to the underlying code without its alteration. See https://stackoverflow.com/a/11753508/12817546. And the code works fine if we remove it. You can still access a method directly as shown by c.Cry(). This is because Go lets you do two things.

First, you can implement an interface implicitly. An interface is simply a set of methods. See https://talks.golang.org/2013/go4python.slide#33. An interface variable can store any non-interface value as long as it implements the interface's methods. See https://blog.golang.org/laws-of-reflection. Values of any type that implement all methods of an interface can be assigned to a variable of that interface. See https://talks.golang.org/2014/taste.slide#20.

c is a variable of cat. cat implements the Eat() and Cry() methods. Eater explicitly implements Eat(). Cryer explicitly implements Cry() and Eat(). Therefore cat implicitly implements the Eater and Cryer interface. See https://talks.golang.org/2012/goforc.slide#40. Thus c a variable of cat can be a variable of Eater and Cryer. See https://golang.org/doc/effective_go.html#blank_implements.

Second, struct and interface types can be embedded in other struct and interface types. See https://golang.org/doc/effective_go.html#embedding. Cryer.Eat(c) calls Eat() since it embeds Eater. Interfaces in Go are thus the primary means for decoupling components of our programs. See https://www.reddit.com/r/golang/comments/6rwq2g. And why interfaces can provide a nice API between packages, clients or servers. See https://stackoverflow.com/a/39100038/12817546.

If you don’t see a benefit, then don’t add an interface. See the comment in https://stackoverflow.com/a/39100038/12817546. There is no explicit hierarchy and thus no need to design one! See https://talks.golang.org/2012/goforc.slide#46. Add an interface when you need it. Define your data types first and build your 1-3 method(s) interface as you go along. See https://stackoverflow.com/a/11753508/12817546. Quotes edited to match example.