What is your opinion of this design decision? What advantages does it have and what disadvantages?
Links:
What is your opinion of this design decision? What advantages does it have and what disadvantages?
Links:
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.)
The Gang of 4 s crucial principle is "prefer composition to inheritance"; Go makes you follow it;-).
The only real uses for inheritance are:
Polymorphism
Borrowing implementation from another class
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 {
AddToBalance(int)
MaxWithdraw() int
}
func Deposit(account Account, amount int) {
account.AddToBalance(amount)
}
func Withdraw(account Account, amount int) error {
if account.MaxWithdraw() < amount {
return errors.New("Overdraft!")
}
account.AddToBalance(-amount)
return nil
}
type BankAccount {
balance int
}
func (account *BankAccount) AddToBalance(amount int) {
account.balance += amount;
}
type RegularAccount {
*BankAccount
}
func (account *RegularAccount) MaxWithdraw() int {
return account.balance //assuming it s allowed
}
type OverdraftAccount {
*BankAccount
overdraft int
}
func (account *OverdraftAccount) MaxWithdraw() int {
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.
Embedding provides automatic delegation. This in itself isn t enough to replace inheritance, as embedding provides no form of polymorphism. Go interfaces do provide polymorphism, they are a bit different than the interfaces you may be use to (some people liken them to duck typing or structural typing).
In other languages, inheritance hierarchies need to be carefully designed because changes are wide sweeping and therefore hard to do. Go avoids these pitfalls while providing a powerful alternative.
Here s an article that delves into OOP with Go a little more: http://nathany.com/good
Folks have requested links to information about embedding in Go.
Here s an "Effective Go" document where embedding is discussed and where concrete examples are provided.
http://golang.org/doc/effective_go.html#embedding
The example makes more sense when you already have a good grasp of Go interfaces and types, but you can fake it by thinking of an interface as a name for a set of methods and if you think of a struct as similar to a C struct.
For more information on structs, you can see the Go language spec, which explicitly mentions nameless members of structs as embedded types:
http://golang.org/ref/spec#Struct_types
So far I ve only used it as a convenient way to put one struct in another without having to use a field name for the internal struct, when a field name wouldn t add any value to the source code. In the programming exercise below, I m bundling a proposal type inside a type that has a proposal and a response channel.
https://github.com/ecashin/go-getting/blob/master/bpaxos.go#L30
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.
I like it.
The language you use affects your thought patterns. (Just ask a C programmer to implement "word count". They will probably use a linked list, then switch to a binary tree for performance. But every Java/Ruby/Python programmer will use a Dictionary/Hash. The language has affected their brains so much that they can t think of using any other data structure.)
With inheritance, you have to build down -- start with the abstract thing, then subclass it to the specifics. Your actual useful code will be buried in a class N levels deep. This makes it hard to use a "part" of an object, because you can t re-use code without dragging in parent classes.
In Go, you can model your classes this way (with interfaces). But you don t (can t) code this way.
Instead, you can use embedding. Your code can be broken up into small, isolated modules, each with their own data. This makes re-use trivial. This modularity has little to do with your "big" objects. (i.e. In Go, you can write a "quack()" method that doesn t even know about your Duck class. But in a typical OOP language, you can t declare "my Duck.quack() implementation has no dependencies on any other methods of Duck.")
In Go, this constantly forces the programmer to think about modularity. This leads to programs that have low coupling. Low coupling makes maintenance much easier. ("oh, look, Duck.quack() is really long and complex, but at least I know that it doesn t depend on the rest of Duck.")
A couple of friends was discussing the use of inheritance and how to check if a subclass is of a specific type and we decided to post it here on Stack. The debate was about if you should implement a ...
Hi I have two classes, one called Instruction, one called LDI which inherits from instruction class. class Instruction{ protected: string name; int value; public: Instruction(string ...
I ve not used C++ in a while, and I ve become far too comfortable with the ease-of-use of real languages. At any rate, I m attempting to implement the Command pattern, and I need to map a number of ...
Suppose I have some code like this: class Base { public: virtual int Foo(int) = 0; }; class Derived : public Base { public: int Foo(int); virtual double Foo(double) = 0; }; ...
What is your opinion of this design decision? What advantages does it have and what disadvantages? Links: Embedding description
I want to extend the FileReference class of Flex to contain a custom property. I want to do this because AS3 doesn t let me pass arguments to functions through event listeners, which makes me feel sad,...
I have the following class structure: class InterfaceA { virtual void methodA =0; } class ClassA : public InterfaceA { void methodA(); } class InterfaceB : public InterfaceA { virtual ...
Consider the Java code below, what would happen if there were no paintComponent method in JPanel class? ... import javax.swing.JPanel; public class ShapesJPanel extends JPanel { public void ...