Why I like Go’s interfaces

When I hear people talk about Go, a lot of the discussions focus on its concurrency features. Whilst it has a good concurrency story, the language landscape is currently filled with languages that have an equally good or better concurrency story – F#, Erlang, Elixir, Clojure, etc…

Personally, what I found really interesting from my time with Go was how its interfaces work. In short, interfaces do not need to be explicitly implemented – i.e. no implement keyword. Instead, interfaces are satisfied implicitly.

 

Duck Typing

In dynamic languages such as Python, you have the concept of Duck Typing.

“if it looks like a duck and quacks like a duck, it’s a duck”

Suppose you have a say_quack  function in Python which expects its argument to have a quack  method. You can invoke the function with any object so long it has the quack  method.

image

Duck typing is convenient, but without a compiler to catch your mistakes you are trading a lot of safety for convenience.

trade_off_1

 

What if there’s a way to get the best of both worlds?

In F#, this can be achieved through statically resolved type parameters:

image

But syntactically, statically resolved TP is kinda clunky and not the easiest to read. Go’s interfaces represent a more elegant solution in my view.

 

Implicitly Implemented Interface

In Go, suppose you have an interface for a Duck:

image

Any struct that has a Quack  method will implement the Duck  interface implicitly and can be used as a Duck.

image

(try it yourself here)

If you have another struct, Dog, which doesn’t have a Quack  method and you tried to use it as a Duck  then you’ll get a compile time error:

image

(try it yourself here)

so there, the convenience of duck typing with the safety of static checking!

trade_off_2

 

Beyond Convenience

The design for Go’s interface stems from the observation that patterns and abstractions only become apparent after we’ve seen it a few times.

So rather than locking us in with abstractions at the start of a project when we’re at the point of our greatest ignorance, we can define these abstractions as and when they become apparent to us.

When you create a new interface, you don’t have to go back and tag every implementation, which sometimes might not be possible if the implementation is owned by a 3rd party.

This makes Go interfaces incredibly cheap, and encourages you to create very granular, precise interface definitions.

 

All and all, even though I don’t enjoy writing code in Go (as you tend to write imperative style of code), I think there are some very interesting ideas and lessons to take from the language.

It’s also a very relevant language of our time, with some important products (ahem, Docker) having been written in Go.

It’s a very small language still, and its website does a good job in helping you get started. Take a tour of Go if you’re interested in learning more about the language.

 

Links

12 Comments

  1. Yan Cui   •  

    In F# I’ll probably have used an interface rather than statically resolved TP to be honest, makes for more readable and idiomatic .Net code.

    .Net interfaces though, are much more expensive in that you have to go around and tag every type that you want to use as that interface (and sometimes you can’t because it might be a BCL class or defined in a 3rd party library).

    With interfaces (whose members should make sense in its local scope) you also tend to overfit for the purpose of the functions that depend on them.

    And then there’s naming… the name of the interface should probably make sense in the context of its implementers rather than the functions that depend on them, otherwise what happens when you rename those functions or remove them? Would the interface names still make sense to whoever looking at the implementing types?

    All and all, interfaces in .Net are still quite a strong form of coupling, but that’s probably more a discussion around the expression problem.

    With Asp.Net vNext they’re experimenting with the idea of assembly neutral interfaces (http://davidfowl.com/assembly-neutral-interfaces-implementation/) which I hear is inspired by Go’s interfaces. But it’s only available on a particular runtime (Asp.net vNext) and seems to solve a different problem.

  2. Nick Lee   •  

    Thanks! What’s your opinion on TypeScript’s interface and duck typing? It is quite similar to Go’s interface.

  3. Colin Svingen   •  

    You have a typo in your second Go listing:

    duck = Bird{}
    duck.Quack() // ~quack ~quack

    should be:

    duck = Daisy{}
    duck.Quack() // ~quack ~quack

    The type `Bird` isn’t declared anywhere.

  4. Yan Cui   •  

    Thanks! Will fix that shortly.

  5. Yan Cui   •  

    I haven’t looked at TypeScript yet, that’s good to know though. Will let you know once I’ve had a chance to spend some time with TypeScript.

  6. Daniel Gerep   •  

    Good article, interfaces are really useful in Go.

    You have a typo on your Dog example, you called the struct Dock instead of Dog =)

  7. Yan Cui   •  

    Thank you, I’ll get that fixed shortly.

  8. Tarcisio Gruppi   •  

    It would be nice to have `func sayQuack` implemented in Go to make it the same as the others.

  9. Yan Cui   •  

    true, that’s a good point, thanks for that, will update the code snippets when I get home

  10. Yan Cui   •  

    there, changed the code snippets to be consistent with the others, thanks again for bringing it up

  11. Pingback: F# Weekly #20, 2015 | Sergey Tihon's Blog

Leave a Reply

Your email address will not be published.