LearnWhy Go Interfaces are Awesome

Jay McGavren
writes on June 28, 2017

Share with your friends










Submit

In object-oriented programming, an “interface” is a description of the things an object can do. Usually, this takes the form of a list of methods an object is guaranteed to have. C# and Java both support interfaces, and so does the Go programming language, but Go’s interfaces are especially easy to use.

You don’t have to declare that a Go type (which can be used kind of like a “class” in other languages) implements an interface, like you do in C# or Java. You just declare the interface, and then any type that happens to have those methods can be used anywhere that interface is required.

Redundant Functions

Let’s suppose that I have a pets package (a “package” is like a “library” in other languages) with Dog and Cat types. A Dog has a Fetch method, a Cat has a Purr method, and most importantly, both dogs and cats have Walk and Sit methods.

package pets

import "fmt"

type Dog struct {
    Name  string
    Breed string
}

func (d Dog) Walk() {
    fmt.Println(d.Name, "walks across the room")
}
func (d Dog) Sit() {
    fmt.Println(d.Name, "sits down")
}
func (d Dog) Fetch() {
    fmt.Println(d.Name, "fetches a toy")
}

type Cat struct {
    Name  string
    Breed string
}

func (c Cat) Walk() {
    fmt.Println(c.Name, "walks across the room")
}
func (c Cat) Sit() {
    fmt.Println(c.Name, "sits down")
}
func (c Cat) Purr() {
    fmt.Println(c.Name, "purrs")
}

Now, let’s create a demo.go program that shows what the Dog and Cat types can do. We’ll create a DemoDog function that takes a Dog and calls its Walk and Sit methods. Then we’ll create a DemoCat function that does the same thing, but for cats.

package main

import "pets"

func DemoDog(dog pets.Dog) {
    dog.Walk()
    dog.Sit()
}

func DemoCat(cat pets.Cat) {
    cat.Walk()
    cat.Sit()
}

func main() {
    dog := pets.Dog{"Fido", "Terrier"}
    cat := pets.Cat{"Fluffy", "Siamese"}
    DemoDog(dog)
    // The above call outputs:
    // Fido walks across the room
    // Fido sits down
    DemoCat(cat)
    // The above call outputs:
    // Fluffy walks across the room
    // Fluffy sits down
}

It’s too bad, though: the DemoDog and DemoCat functions are exactly the same, except that one takes a Dog and the other takes a Cat. Repeating code like that increases the risk of inconsistencies, since you might change one function but forget to update the other. It would be nice if we could get rid of DemoCat and just pass a Cat to DemoDog, but we’ll get an error if we try that:

DemoDog(cat)
// ./demo.go:19: cannot use cat (type pets.Cat)
// as type pets.Dog in argument to DemoDog

Enter the Interface

But we don’t have to maintain two nearly-identical functions, just because they take different types. This is exactly the problem that interfaces are meant to solve.

We’ll just create a FourLegged interface that includes all types with Walk and Sit methods. Then we’ll replace the DemoDog and DemoCat functions with a single Demo function that takes any FourLegged value (whether it’s a Dog or a Cat).

package main

import "pets"

// This interface represents any type
// that has both Walk and Sit methods.
type FourLegged interface {
    Walk()
    Sit()
}

// We can replace DemoDog and DemoCat
// with this single function.
func Demo(animal FourLegged) {
    animal.Walk()
    animal.Sit()
}

func main() {
    dog := pets.Dog{"Fido", "Terrier"}
    cat := pets.Cat{"Fluffy", "Siamese"}
    Demo(dog)
    // The above call (again) outputs:
    // Fido walks across the room
    // Fido sits down
    Demo(cat)
    // The above call (again) outputs:
    // Fluffy walks across the room
    // Fluffy sits down
}

The Awesome Part

We didn’t have to update the Dog or Cat types to declare that they implement the FourLegged interface (like we would in C# or Java). We didn’t even have to open the pets package. We just declared our interface right there in our main program, right above the function where we use it. And because they both have Walk and Sit methods, the Dog and Cat types are automatically usable any place in our code that calls for a FourLegged value!

Go interfaces are a low-ceremony way to keep the safety of static typing (like you see in C# or Java), while still offering most of the flexibility of dynamic typing (like in JavaScript or Python). And they’re just one of the language’s many programmer-friendly features. If you’re suitably impressed, you should look into Go further; you won’t be disappointed!

P.S.: I’ve made the code from this post available in a Treehouse Workspaces snapshot. You can try running the code right from your browser by forking it and typing go run demo.go in the workspace console.

P.P.S: This post was adapted from Go Language Overview. It’s our new course for developers already proficient in programming, who want a quick primer on Go. We’ll be releasing courses for beginning Go programmers too, so keep an eye on our library!

Start learning to code today with a free trial on Treehouse.

3 Responses to “Why Go Interfaces are Awesome”

  1. Great post. We’re featuring this in our news letter: https://betterdev.link/issues/6 to help other people find out it.

  2. Go doesn’t have classic Object Oriented concept of classes and inheritance. Interfaces in Go provide a way to specify the behavior of an object: do like this and reuse it.

Leave a Reply

Learning to code can be fun!

Get started today with a free trial and discover why thousands of students are choosing Treehouse to learn about web development, design, and business.

Learn more