views:

493

answers:

4

What is your opinion of this design decision? What advantages does it have and what disadvantages?

Links:

+11  A: 

The Gang of 4's crucial principle is "prefer composition to inheritance"; Go makes you follow it;-).

Alex Martelli
Inheritance is overused, and I appreciate how Go simplifies the composition, but the question I'd really like to know is if embedding can replace inheritance completely. I guess this is a difficult question to answer without actually going and writing some code
Casebash
Well, you don't (directly) get some key inheritance-hinged design patterns, such as Template Method, but that wouldn't seem to be a killer -- in the very worst case, it would appear to entail the loss of some convenience (requiring slightly more explicit coding).
Alex Martelli
+3  A: 

The only real uses for inheritance are:

  • Polymorphism

    • Go's interface's "static duck typing" system solves this problem
  • Borrowing implementation from another class

    • This is what embedding is for

Go's approach doesn't exactly map 1-to-1, consider this classical example of inheritance and polymorphism in Java (based on this):

//roughly in Java (omitting lots of irrelevant details)
//WARNING: don't use at all, not even as a test

abstract class BankAccount
{
    int balance; //in cents
    void Deposit(int money)
    {
        balance += money;
    }

    void withdraw(int money)
    {
        if(money > maxAllowedWithdrawl())
            throw new NotEnoughMoneyException();
        balance -= money;
    }

    abstract int maxAllowedWithdrawl();
}

class Account extends BankAccount
{
    int maxAllowedWithdrawl()
    {
        return balance;
    }
}

class OverdraftAccount extends BankAccount
{
    int overdraft; //amount of negative money allowed

    int maxAllowedWithdrawl()
    {
        return balance + overdraft;
    }
}

Here, inheritance and polymorphism are combined, and you can't translate this to Go without changing the underlying structure.

I haven't delved deeply into Go, but I suppose it would look something like this:

//roughly Go? .... no?
//for illustrative purposes only; not likely to compile
//
//WARNING: This is totally wrong; it's programming Java in Go

type Account interface
{
    func addToBalance(int);
    func maxWithdraw();
}

func Deposit(account *Account, amount int)
{
    account.addToBalance(amount)
}

func Withdraw(account *Account, amount int)
{
    if account.maxWithdraw() > amount
    {
        return os.Errno(1); // API?
    }
    account.addToBalance( -amount );

    return os.Errno(0); // API?
}

type BankAccount
{
    balance int;
}

func (account *BankAccount) addToBalance(int amount)
{
    account.balance += amount;
}

type RegularAccount
{
    *BankAccount;
}

func (account *RegularAccount) maxWithdraw()
{
    return account.balance; //assuming it's allowed
}

type OverdraftAccount
{
    *BankAccount;
    overdraft int;
}

func (account *OverdraftAccount) maxWithdraw()
{
    return account.balance + account.overdraft;
}

As per the note, this is totally a wrong way to code since one is doing Java in Go. If one was to write such a thing in Go, it would probably be organized a lot different than this.

hasen j
+2  A: 

I am just now learning about Go, but since you are asking for an opinion, I'll offer one based on what I know so far. Embedding appears to be typical of many other things in Go, which is explicit language support for best practices that are already being done in existing languages. For example, as Alex Martelli noted, the Gang of 4 says "prefer composition to inheritance". Go not only removes inheritance, but makes composition easier and more powerful than in C++/Java/C#.

I've been puzzled by comments like "Go provides nothing new that I can't already do in language X," and "why do we need another language?" It appears to me that in one sense, Go doesn't provide anything new that couldn't be done before with some work, but in another sense, what is new is that Go will facilitate and encourage the use of the best techniques that are already in practice using other languages.

Greg Graham
In some ways, what is new in Go is what has been taken away - that is a key reason for a new language. If they were only adding features, it could have been C+++ ;) but to take away features (inheritance, pointer arithmetic, manual memory allocation) requires a new language.
Hamish Downer
+2  A: 

In a comment, you wondered if the embedding idea was enough to "replace inheritance completely". I would say the answer to that question is "yes". A few years ago I played very briefly with a Tcl OO system called Snit, which used composition and delegation to the exclusion of inheritance. Snit is still vastly different from Go's approach, but in that one respect they have some common philosophical ground. It's a mechanism for joining together pieces of functionality and responsibility, not a hierarchy for the classes.

As others have stated, it's really about what kind of programming practices the language designers want to support. All such choices come with their own pros and cons; I don't think "best practices" is a phrase that necessarily applies here. We will probably see someone develop an inheritance layer for Go eventually.

(For any readers familiar with Tcl, I felt Snit to be a slightly closer match to the "feel" of the language than [incr Tcl] was. Tcl is all about the delegation, at least to my way of thinking.)

Zac Thompson