*struct embedding* is *multiple inheritance*? - understanding golang

2,032 views
Skip to first unread message

Lucio M. Tato

unread,
Feb 6, 2015, 8:32:17 AM2/6/15
to golan...@googlegroups.com
I'm writing a document to help myself understanding golang and maybe help others.
I'm trying to relate golang-concepts with classical OOP concepts.

I've concluded (maybe I'm wrong) that ***struct embedding*** is ***multiple inheritance***


I need help from people with a better understanding of golang internals.

Is my conclusion correct? do ***struct embedding*** is ***multiple inheritance*** ?

Thanks.

Haddock

unread,
Feb 6, 2015, 8:54:53 AM2/6/15
to golan...@googlegroups.com
Hello,

embedding in Go is the same as delegation. In Go the compiler does the forwarding of the method calls to the struct being delegated to for the user, which is called embedding. The user does not have to the wiring on his own as in most OO languages. See the section "Inheritance" in this Go primer.

There is no multiple inheritance in Go, even no single inheritance. Inheritance means that an inherited method is "overwritten", rather than being delegated to. This is not in the Go language as with OO languages (extends statement in Java, et.al.), but it can be done. As Go has interfaces it also has dynamic dispatch and this way method overwriting can be implemented. This blog describes a way to get this accomplished.

-- Haddock

Egon

unread,
Feb 6, 2015, 9:57:42 AM2/6/15
to golan...@googlegroups.com


On Friday, 6 February 2015 15:54:53 UTC+2, Haddock wrote:
Hello,

embedding in Go is the same as delegation

s/delegation/forwarding/

Delegation assumes the original receiver to handle any questions by the method, whereas with forwarding someone else handles the message questions (i.e. the embedded struct). (Original source of delegation http://web.media.mit.edu/~lieber/Lieberary/OOP/Delegation/Delegation.html)

Lucio M. Tato

unread,
Feb 6, 2015, 1:44:58 PM2/6/15
to golan...@googlegroups.com
Thanks Haddock for your very clear answer and useful links.

I've tried samples in the links, and code of my own, *and now I see* that *struct methods* in golang are always *non-virtual*. 

Since *struct methods* in golang are always *non-virtual*, when you *embed* a struct and you define the same method as the base, you're "shadowing" the method and not "overriding it" (you cannot override methods since there are no *virtual* methods in *golang structs*) 
 
What I conclude is that ** *struct methods* in golang are always *non-virtual* **

Given that, *embedding IS multiple inheritance* ***still holds***. 

When you embed one or more structs, you *inherit* all fields and methods of all the embedded structs (noting that the "structs methods" are always non-virtual)

Considering that *struct methods* in golang are always *non-virtual*, 
do you think that saying "*embedding IS multiple inheritance*" is correct? 

Best regards

Stanislav Paskalev

unread,
Feb 6, 2015, 1:53:57 PM2/6/15
to golan...@googlegroups.com
No, because embedding is not inheritance. You cannot access an outer struct from an inner.

Regards,
Stan

Lucio M. Tato

unread,
Feb 6, 2015, 2:20:53 PM2/6/15
to golan...@googlegroups.com
What you're saying reinforces "to embed is to inherit", see:

In embedding: "You cannot access an outer struct from an inner"

In inheritance: "you cannot access the child/derived class from the parent/base class"

So:
 - "the outer struct" is the "child class"
 - "the inner struct" is the "parent class"
 - and then "to embed is to inherit"

Note: "to embed is to inherit" holds only if you say also: "all struct methods are non-virtual"

Best regards

Stanislav Paskalev

unread,
Feb 6, 2015, 2:29:31 PM2/6/15
to golan...@googlegroups.com
Inheritance includes overriding methods on the parent object from the child. See http://play.golang.org/p/2pGMEiWUIN - this does not happen in Go. Ergo there is no inheritance. Only delegation. See Plan 9's C dialect for a history lesson on this feature :)

Regards,
Stan

Lucio M. Tato

unread,
Feb 6, 2015, 3:30:55 PM2/6/15
to golan...@googlegroups.com
Stanislav, let me first make clear that my intention is to make golang easier to understand (for me and maybe for others coming from OOP). I am not attacking golang, and I do not want to argue with you for the sake of arguing.

You say:
>Inheritance includes overriding methods on the parent 
Thats not correct, you must differentiate "Inheritance" from "subtyping".  see: https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)

I believe golang is solving problems with OOP by means of very good pragmatic simplifications, and its working great!!!.

I want to understand *how* does golang simplifies OOP 

In your sample, you're showing me that "embedding" is also "composition".
You're using "dot" to access the "base class". The example does what is expected to do, 
even if you say "b is inheriting from a"


ON THE OTHER HAND, There are more complex examples (constructed from Haddock answer), check this: 

The thing to note here, is that "all struct methods are non-virtual", 
so this example: also acts "as expected" when you say "embedding is inheritance"

The sample can "surprise" someone coming from Java, because in Java class methods are by-default *virtual*,
but if you say to them: "all struct methods are non-virtual"
they will understand perfectly that "embedding is like multiple inheritance"

Regards

Egon

unread,
Feb 6, 2015, 4:18:21 PM2/6/15
to golan...@googlegroups.com


On Friday, 6 February 2015 22:30:55 UTC+2, Lucio M. Tato wrote:
Stanislav, let me first make clear that my intention is to make golang easier to understand (for me and maybe for others coming from OOP). I am not attacking golang, and I do not want to argue with you for the sake of arguing.

You say:
>Inheritance includes overriding methods on the parent 
Thats not correct, you must differentiate "Inheritance" from "subtyping".  see: https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)

AFAIK inheritance assumes that the inherited methods all have the same receiver, which Go doesn't have: http://play.golang.org/p/LkiY-1pp3S

Although, I haven't traced the origin of inheritance to say for certain.

+ Egon

Haddock

unread,
Feb 6, 2015, 4:48:46 PM2/6/15
to golan...@googlegroups.com
Hi Lucio,

glad my reply was useful. See my comments below.


Am Freitag, 6. Februar 2015 19:44:58 UTC+1 schrieb Lucio M. Tato:
Thanks Haddock for your very clear answer and useful links.

I've tried samples in the links, and code of my own, *and now I see* that *struct methods* in golang are always *non-virtual*. 

Since *struct methods* in golang are always *non-virtual*, when you *embed* a struct and you define the same method as the base, you're "shadowing" the method and not "overriding it" (you cannot override methods since there are no *virtual* methods in *golang structs*) 
 
What I conclude is that ** *struct methods* in golang are always *non-virtual* **

Yes, that's correct.
 

Given that, *embedding IS multiple inheritance* ***still holds***. 

When you embed one or more structs, you *inherit* all fields and methods of all the embedded structs (noting that the "structs methods" are always non-virtual)

Considering that *struct methods* in golang are always *non-virtual*, 
do you think that saying "*embedding IS multiple inheritance*" is correct?

The Go primer I referred to in my previous reply explains this very well. In the chapter named "Inheritance" there is a section that starts with: "This composition is achieved via delegation, not inheritance.". In this section the following sample code is displayed:

type Base struct {}
func (Base) Magic() { fmt.Print("base magic") }
func (self Base) MoreMagic() {
  self.Magic()
  self.Magic()
}

type Foo struct {
  Base
}
func (Foo) Magic() { fmt.Print("foo magic") }

f := new(Foo)
f.Magic() // prints "foo magic"
f.MoreMagic() // prints "base magic base magic" and not "foo magic foo magic"

The point is that f.MoreMagic() in the last line prints "base magic base magic" and not "foo magic foo magic". This is because Foo.Magic() apparently does not overwrite Base.Magic(). From that we can conclude that delegation is taking place and not inheritance.

Again, you can mimic inheritance as explained in that blog I mentioned in my previous post. It is simply not directly supported by the Go language. This is because Robert Pike is known not to be fond of OOP.

Lucio M. Tato

unread,
Feb 6, 2015, 9:49:10 PM2/6/15
to golan...@googlegroups.com
Hi Haddock,
I've seen the sample, even I write one myself:  http://play.golang.org/p/_TCsHrITp-

But what is happening in this example is *method shadowing* (or method hiding), 
***This does not rule out inheritance.***

Please read this article on C#, describing exactly the same situation:

In the case of C#, the default behavior is the same as golang.

So, when the article "Gogle Go, A primer" says:
> ... From that we can conclude that delegation is taking place and not inheritance.

It is not correct. What you conclude from the example is that: "golang embedding implies *inheritance with method shadowing*"

Since golang behaves exactly as C# in this case  (and we agree that in C# has "inheritance")
we conclude that in golang the situation can also be named "inheritance with method shadowing".

Thanks again. This has helped me a lot.  
This conversation do not change what golang does, but I believe can be helpful to explain (to a C# programmer for example)
that "golang embedding is multiple inheritance". I'll try to include all this info in my document: https://github.com/luciotato/golang-notes/blob/master/OOP.md

My next question, derived from all the kind answers from golang-nuts is:
"is embedding also composition"?

This new question seems a little less controversial. I'll try to write some examples and counter-examples
and I will open a new topic soon. 
If the answer is "yes" is means that golang-embedding is a clever "new" concept which
includes good parts from "inheritance" and "composition", *without the problems!!".  

That's a great win for golang, and that's why I want to explain golang-embedding in terms of classical OOP.

Thanks again to all in golang-nuts.


Haddock

unread,
Feb 7, 2015, 3:29:34 AM2/7/15
to golan...@googlegroups.com


Am Samstag, 7. Februar 2015 03:49:10 UTC+1 schrieb Lucio M. Tato:
Hi Haddock,
I've seen the sample, even I write one myself:  http://play.golang.org/p/_TCsHrITp-

But what is happening in this example is *method shadowing* (or method hiding), 
***This does not rule out inheritance.***

The point is that your sample in http://play.golang.org/p/_TCsHrITp- does not have an equivalent method to the MoreMagic method as in the sample of the Go Primer where it very importantly calls Magic:


func (self Base) MoreMagic() {
  self.Magic()
  self.Magic()
}

This makes all the difference. Otherwise the difference between delegation and inheritance does not open up. I think a good idea to grok this would be to run the sample code from the Go Primer and the sample code from the blog. Eventually step through the code with the debugger and then you will get it :-).


Haddock

unread,
Feb 7, 2015, 3:45:10 AM2/7/15
to golan...@googlegroups.com

Something I should have mentioned: Magic() needs to be implemented in Base and Foo, e.g. in your example in parent and child.

Cheers, Haddock

Oliver Plohmann

unread,
Feb 7, 2015, 11:26:10 AM2/7/15
to golan...@googlegroups.com
As I often have read discussions in this forum about Go being object-oriented now or not I sad down to write a blog post that explains the matter: Is Google's Go object-oriented now or not? It turned out a bit long, sorry. But I hope it sheds some light on this ever re-occuring issue.

Cheers, Oliver

Lucio M. Tato

unread,
Feb 7, 2015, 11:37:53 PM2/7/15
to golan...@googlegroups.com
Haddock:

In my example "func magic" is "func simple", and it is implemented in both, parent and child.

Both examples *show the same thing*, that *parent methods are hidden but NOT overridden* 

Here's the blog example: (base magic) http://play.golang.org/p/KrLR2xlPRU

-- ***we agree on this*** --

I *do understand* that on struct-embedding *parent methods are NOT overridden* 

but maybe we do not have the same definition of what "inheritance" includes.

For what I know "inheritance" *do not implies* method overriding. 
i.e., you can "inherit" from a parent-class and by default "hide" instead of "override" parent methods.

C# has inheritance *and the default behavior is exactly the same as golang struct-embedding*
Check this article please:
Here's the key part:
>Since the JewelThief class inherits from Locksmith and replaces the ReturnContents() method with its own method, it looks like JewelThief is >overriding Locksmith's ReturnContents() method. But that's not actually what's happening. You probably expected JewelThief to override the >method (which we'll talk about in a minute), but instead JewelThief is hiding it.

Since C# "inheritance" *behavior is exactly the same as golang struct-embedding*
I conclude that golang struct-embedding is "inheritance WITHOUT virtual methods"

The key premises here are:
a.- you CAN have inheritance without method overriding (as C# default behavior)
b.- you CANNOT have inheritance without method overriding.

I understand that "a" is true and "b" is false.
do you agree?

The problem is that if you say that "b" is true, then C# default "inheritance" is not "inheritance".

Regards

thwd

unread,
Feb 8, 2015, 9:11:54 AM2/8/15
to golan...@googlegroups.com
Lucio,



there's one key point that hasn't been considered in this thread:

In traditional "OOP" if A extends B, then A is subtype of B i.e. polymorphism permits A to be used where a B is expected or, in simple words, "A is a B".
This always holds: A cannot decide to *not* be a B by making a public method private or whatever.

Go only "understands" as subtypes:
 - Implementations of interfaces as subtypes of said interfaces.
 - Interfaces (A) as subtypes of other interfaces (B) where B defines a super set of the method set of A.

This means that if you embed a struct type B in a struct type A, then A is not a subtype of B.
Similarly, if you embed a interface type C in A, then A is a C only as long as A does not "overwrite" a method name of C with a different signature.



Tom

Lucio M. Tato

unread,
Feb 8, 2015, 3:53:16 PM2/8/15
to golan...@googlegroups.com
Tom: At first I was holding the same position as you, but later, searching for precise terms definitions I've found that:

>Inheritance should not be confused with subtyping.[1] In some languages inheritance and subtyping agree,[a] while in others they differ; in general subtyping establishes an is-a relationship, while inheritance only reuses implementation and establishes a syntactic relationship, not necessarily a semantic relationship (inheritance does not ensure behavioral subtyping). To distinguish these concepts, subtyping is also known as interface inheritance, while inheritance as defined here is known as implementation inheritance.

It seems to be (if the wikipedia article is correct) that: "inheritance" is a code-reuse mechanism, while "subtyping" is the "IS-A" relationship, so "inheritance" is not "subtyping"

In golang;
 - "embedding" seems to be "inheritance without virtual methods"
while
 -  *implementing an Interface* seems to be "subtyping", i.e.: establish an IS-A relationship with the interface. 

In golang, by having this two mechanisms separated, I believe you get: 
  a.- more flexibility (with interfaces, via method dispatch)
  b.- more speed (with struct-embedding, because all method calls compile to static calls)

It is interesting, I'm trying to understand now what "embedding and interface" could mean, and a valid use-case for it.

Best regards.

Haddock

unread,
Feb 9, 2015, 3:29:58 AM2/9/15
to golan...@googlegroups.com

Go's structs support aggregation and delegation, but not inheritance.

http://www.drdobbs.com/open-source/go-tutorial-object-orientation-and-gos-s/240005402

wkharold

unread,
Feb 9, 2015, 2:33:45 PM2/9/15
to golan...@googlegroups.com
You are making it harder on yourself by trying to map a "classical OOP concept" onto go. That mapping is not going to be successful, or really very helpful, since go doesn't follow the "classical OOP" model.

Go doesn't necessarily simplify OOP. On a good day it simplifies the construction of a particular application.
Reply all
Reply to author
Forward
0 new messages