In my continuing obsession with learning a new language, I’ve gotten to the point in experimenting with Go that I want to know what all this implicit interface stuff is about. In my previous blog post, I talked about how Go doesn’t actually have classes, but rather it has explicit receiver functions that look like they are methods being invoked on an object.

The rumor on the street is that Go has a facility similar to duck typing in that when you declare an interface, anything can be said to implement that interface as long as that thing has all of the method definitions declared in the interface. This isn’t entirely unique – dynamic languages are full of stuff like this and Scala’s got the ability to define type aliases that do the same thing. The curious thing about Go’s implicit interface satisfaction is that it is compile-time checked. That’s right – your code won’t compile if you have code that attempts to convert an object into an interface that it can’t satisfy.

Let’s take a real-world example: wielding a chair (what, that’s not real-world to you?). When building MUDs and even some more modern game types, you often run into this type of thing. If a developer didn’t originally intend for an object to be used as a weapon, it can’t be treated like one. But, what if you want to make it so that the player can wield a chair as easily as a sword? Sure, they will have different behavioral characteristics, but you should still be able to wield either.

In a classic programming language problem, this is easy to solve: Create an interface called Wieldable (or IWieldable if you’re a .NET person) and then two classes that both implement that interface: Chair and Sword. In Go, you still create a Wieldable interface that defines a Wield() method, but the difference is you never create a class nor do you explicitly indicate what interface you’re implementing. If there’s an explicit receiver in scope called Wield() for that object, then your code can treat it as a wieldable.

Let’s take a look at some code:

// interfaces
package main

import (
	"fmt"
)

type Wieldable interface {
	Wield()
}

type Chair struct {
	Legs	int
	Wielded bool
	Name	string
}

type Sword struct {
	DamageRating	int
	Wielded			bool
	Name			string
}

type Test struct {
	Wieldy		Wieldable
}

func (s *Sword) Wield() {
	fmt.Printf("Wielding Sword %s\n", s.Name)
	s.Wielded = true
}

func (c *Chair) Wield() {
	fmt.Printf("Wielding Chair %s\n", c.Name)
	c.Wielded = true
}

func main() {
	fmt.Println("Hello World!")

	s := Sword{
		DamageRating: 12,
		Wielded: false,
		Name: "Sword of Doom",
	}

	c := Chair{
		Legs: 4,
		Wielded: false,
		Name: "Death Seat",
	}

	t := Test {
		Wieldy: &s,
	}

	t2 := Test {
		Wieldy: &c,
	}

	t.Wieldy.Wield()
	t2.Wieldy.Wield()
}

In this code I am creating a Sword struct and a Chair struct and then I created an interface called Wieldable and another struct called Wieldy which holds a Wieldable object. To prove that I can convert between Chair/Sword and Wieldable, I create two test objects – each holding a Wieldable converted from either a sword and I then call the Wield() method on each.

So here’s something unexpected – this is a one-way conversion. In a runtime managed language when you typecast a reference to an object from one type to another, the actual underlying object remains unchanged and you get a runtime-limited view onto that object. For example, if you’ve created some serializable object called Zombie, you can cast that to a Serializable and then still get back the original zombie. If you attempt to get a Sword object out of a Test.Wieldy field, you will get an error message from the compiler.

That said, you can still prove that the wield methods did actually change the value of the things you’re wielding:

fmt.Printf("Wield status: %s, %s", s.Wielded, c.Wielded)

The big take-away that I learned from this experiment is that while implicit interfaces are pretty damn awesome, you should not be using them so you can do a pile of random typecasting or to somehow treat your structs like the target for mixins (traits in Scala). They should be used to assert that a particular set of receiver methods exist for a particular data type. And since there are no classes and there is no inheritance, that data type is strictly enforced.

Further, I might have been better off just using embedding to contain a wieldable inside either my chair or sword objects, which would make them both wieldable. Also, interfaces cannot contain fields. So you might be tempted to try and model some statement like “anything wieldable should have a wielded boolean property”. You cannot model this with interfaces.

So I’m already starting to run into scenarios where it feels awkward or downright limiting to model things like business logic (or game logic) in Go. I will keep trying, however, to see if there’s a more Go-idiomatic way of doing things that I’m not seeing because I’m still knee-deep in the class-and-inheritance world.