Coupling classes to interfaces
Sunday 23 October 2011 09:49
Over on the 8th Light blog, Steven Degutis discusses the advantages of Go's approach to interfaces. Specifically, Go allows you to have a class implement an interface without explicitly mentioning the interface so long as it has methods with the right names and type signatures. He likes the idea you can write an interface, and have an existing class implement that interface without modification. I find the idea that a class can implement an interface just by the coincidence of having methods with matching names and type signatures to be terrifying.
To re-use Steven's example:
type Predator interface { chasePrey(Prey) bool eatPrey(Prey) } type Lion struct{} func (self Lion) chasePrey(p Prey) bool { // ... } func (self Lion) eatPrey(p Prey) { // ... }
Since Lion
has the methods chasePrey
and eatPrey
with the correct type signature, it implements the interface Predator
, yet the interface Predator
is never mentioned in the definition of Lion
. This is considered a Good Thing: to quote Steven:
But alas, in Java, the class itself must know ahead of time all the names of the interfaces it wants to conform to. This is an unfortunate form of temporal coupling.
[…]
Go doesn't care that, 5 years ago, Lion never specified which interfaces it implements, it just cares that it has the methods this interface needs, and rightly so.
I think it's a terrifying idea that my class could suddenly start implementing new interfaces that I'd never considered when writing the class. When I define an interface in Java, it has more meaning than just the name and type signature of each method. An interface is also a contract for the behaviour of the implementation of those methods, which can't be verified by names and types alone. I want to explicitly specify the interfaces that a class implements, as a declaration in the code that says “I understand what behaviour sub-types of the interface should have, and I've done my best to make sure that this class implements that behaviour”. To me, this is much more useful than knowing the type of a class is compatible with an interface.
Now, I'm not saying that Go has got it wrong. I think Go's interfaces provide weaker contracts in exchange for greater flexibility, but which is better depends on your programming style and preferences.
Topics: Software design