Interfaces in Go

Interfaces in Go and how they compare to other languages you’re familiar with

Go is a strongly typed language, which doesn’t support generics. Although not your common object oriented language like java, go does support types and methods on those types. There are no constructors, inheritance. The whole idea is to intentionally keep it light weight. Interface is something similar to what you’ve in other languages. This is how you define them:

package io

type Writer interface {
    Write(p []byte) (n int, err error)
}

Interfaces are contracts:

There is another kind of type in Go called an interface type. An interface is an abstract type. It doesn’t expose the representation or internal structure of its values, or the set of basic operations they support; it reveals only some of their methods. When you have a value of an interface type, you know nothing about what it is; you know only what it can do, or more precisely, what behaviors are provided by its methods.

As is expected, if a function expects io.Writer as argument. We can pass any of the concrete type which implements io.Writer to it. And based on the actual type, same function can either write to os.Stdout or a file or a string buffer. Thus, exhibiting polymorphism.

So how do concrete types implement a particular interface. Well it need not to. Go interfaces are implicitly satisfied if a particular concrete type implements the methods of the interface (For example, if os.File implements a Write method with signature similar to above, it satisfies that interface). This way you can define a new interface and existing types will still satisfy it, if they support all methods. This is particularly usefully if you don’t own those types.

Internals

Interface internally consists of two values: dynamic type and dynamic value. Like other types, interfaces are initialized, by default, to well defined value, where both type and value are nil:

var w io.Writer

Full-width image

An interface is nil when it’s type value is nil. Just like pointers & other aggregate types, interfaces can be compared to nil (i.e., w == nil or w != nil).

Interfaces can only be assigned to types which support all methods defined by the interface.

var w io.Writer
// os.Stdout is *os.File pointing to standard output
w = os.Stdout

On assignment, type of interface value get set to the actual concrete type & value to it’s actual value.

When we execute a method on interface,

w.Write([]byte("hello"))

compiler infers the address of the method from the actual concrete type and calls it with value as receiver. So w.Write internally executes (*os.File).Write.

Equality

Interface can be compared for equality using == & !=. Two interfaces are equal if both their type and value are equal.


© 2019. Hosted with ♥ on Github

Powered by Hydejack v8.4.0