4 ms·
Go actually does implement inheritance, albeit in a roundabout sort of way: a struct can have one or more base members, and any method defined on the base membe
by simiones 5y ago
Go actually does implement inheritance, albeit in a roundabout sort of way: a struct can have one or more base members, and any method defined on the base members is accessible from the new struct implicitly, so they also implicitly implement any interface that was implemented by their base members.
Here's an example (in the playground, because it gets a bit long): https://play.golang.org/p/TblQypAbIL2 https://play.golang.org/p/TblQypAbIL2
- throwaway894345 5y agoThat's not inheritance, it's just syntax sugar that lets a struct delegate method calls to one of its members. In other words: struct Foo {} func (f *Foo) baz() { println("Foo.baz()") } func (f *Foo) qux() { f.baz() } Given the above, `struct Bar { Foo }` is the same as: struct Bar { Foo Foo } // field called `Foo` of type `Foo` func (b Bar) baz() { b.Foo.baz() } func (b Bar) qux() { b.Foo.qux() } Since it's just syntax sugar and not inheritance, we can't put a `Bar` in a list of `Foo`s nor can we pass a `Bar` into a function that expects a `Foo`. It also means that if Bar overrides its `baz()` method like so: func (b Bar) baz() { println("Bar.baz()") } that calling `Bar.qux()` will still print "Foo.baz" and not "Bar.baz" (most languages with inheritance will print "Bar.baz", which is to say methods are virtual by default).
- tsimionescu 5y agoUsing interfaces, you easily get polymorphism as well: type FooI interface{ baz(); qux(); } foos := []FooI{&Foo{}, &Bar{}} Regarding overriding, you're right that it doesn't work out of the box. However, you can make "extensible classes" with just a little boilerplate: type Foo struct {FooI this} func (f *Foo) baz() { println("Foo.baz()") } func (f *Foo) qux() { f.this.baz() } func NewFoo() Foo { f := Foo{}; f.this = &f; return f } Now, to extend Foo: type Bar struct {Foo} func (b *Bar) baz() { println("Bar.baz()") } //the override func NewBar() Bar { b := Bar{}; b.Foo.this = &b; return b } //this would work even if we didn't override baz func main() { foo := NewFoo() bar := NewBar() foos := []FooI{&foo, &bar} for _,f := range foos { f.qux() } //prints Foo.baz(), then Bar.baz() } Since best practice even in C++ or C# or Java is to only allow inheritance for classes that are designed with it in mind, and since Go anyway has lots of other boilerplate, this shouldn't be unbearable if required. Playground link for anyone curious: https://play.golang.org/p/SKGhANuBGgB https://play.golang.org/p/SKGhANuBGgB
- throwaway894345 5y agoyeah, you absolutely can emulate this stuff to a large degree. My point wasn't that it's impossible, but rather you have to build it from orthogonal primitives. And even then I don't think you can get the same degree of trampolining that you can get with inheritance (for example, we can get Bar.qux() to call Foo.baz() easily enough via interfaces, but then IIRC it's trickier to get Foo.baz() to call Bar.asdf()--that said I'm too busy to think it through properly).