Go revelations

|
|

Hoo boy.  There are some things which need to percolate in my subconscious for a while before I figure them out; when my brain accomplishes this feat, it’s a thoroughly enjoyable revelation.  When I was 20, it would happen in hours, or overnight; now it seems to take a bit longer (a couple of days), but I still enjoy it just as much.

Go has a sort of multiple inheritance based on a rule called shallowest-first.  Basically, it means that the compiler determines which function to use based on how many type indirections it has to go through to get to a function.  For example:

type F struct { }
func (f F) foo() {}
Here, f.foo() has a depth of 1 (you only have to dig down one type to get to it).  If type G inherits from F:
type G struct {
   F
}
then g.foo() has a depth of 2 – you there’s no foo() directly on G, but there is one on the anonymous field F.  Remember, g.foo() is really just an alias for g.F.foo() – count the points, and you have the depth.  And this is where the magic happens.  So consider:
type Dog struct {}
func (d Dog) bark() {}
func (d Dog) wag() {}  
type Fox struct {}
func (f Fox) bark() {}
func (f Fox) burrow() {}
Now say you want (for some reason) to have a Gopher object that barks and wags like a Dog, but also burrows like a Fox?
type Gopher struct {
    Dog
    Fox
}
This is illegal: the rules of Go say you can’t have two functions at the same depth, and the bark()s here conflict. In this case, you have two depth-2 barks().  But here’s what you can do:
type deeperFox struct {
    Fox
}
type Gopher struct {
    Dog
    deeperFox
}
Now, the Fox functions are one deeper than the Dog functions; it’s now legal, the compiler is happy, and it is clear which bark() will be called.  If you really mean Fox.bark(), you can still get at it with g.deeperFox.bark().

When I first came across this in code, I couldn’t figure out why someone would do this.  The Go specification section on selectors wasn’t a whole lot of help in this case, at least for me.  I find this sort of thing a little bit hacky, but it works, it doesn’t require a lot of code, and it is straight-forward.  Much like the rest of Go.

Copyright © Sean Elliott Russell

comments powered by Disqus