joaodlf.com


Go: The Diamond Problem

I’ve witnessed some of the online debate when it comes to Go and OOP. Some people say the language is object-oriented, others don’t share that view. I think it’s safe to say that Go isn’t a traditional object-oriented language.

Lately, I’ve been trying to learn more about Go from an OOP perspective - It’s what I have most experience in. In fact, all of the languages I have worked with on a professional setting follow typical OOP standards (until now!).

After diving into structs and interfaces, as well as concepts like embedding (inheritance?), I was left wondering: How does Go solve the diamond problem?

The “diamond problem” is an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C. If there is a method in A that B and C have overridden, and D does not override it, then which version of the method does D inherit: that of B, or that of C?

Ok, so Wikipedia has a pretty clear explanation on how Go handles it:

Go prevents the diamond problem at compile time. If a structure D embeds two structures B and C which both have a method F(), thus satisfying an interface A, the compiler will complain about an “ambiguous selector” if D.F() is called, or if an instance of D is assigned to a variable of type A. B and C’s methods can be called explicitly with D.B.F() or D.C.F().

Essentially, Go ‘solves’ the problem at compile time: It just won’t allow you to do it. The method has to be called explicitly or not at all.

Personally, I think this is a good solution. It avoids ambiguity and confusing code - There is already plenty of that going around!

A practical example (also available at play.golang.org

package main

import "fmt"

type A interface {
    F()
}

type B struct {
    A
}

func (b B) F(){
    fmt.Println("F() of B")
}

type C struct{
    A
}

func (c C) F(){
    fmt.Println("F() of C")
}


type D struct {
    B
    C
}

func main(){
    d := D{}

    // Error! "ambiguous selector d.F".
    // d.F()

    // Allowed!
    d.B.F()
    d.C.F()
}
comments powered by Disqus