Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang and inheritance

I want to provide a base struct with methods in my library that can be 'extended'.

The methods of this base struct rely on methods from the extending struct. This is not directly possible in Go, because struct methods only have acces to the structs own fields, not to parent structs.

The point is to have functionality that I do not have to repeat in each extending class.

I have come up with this pattern, which works fine, but looks quite convoluted due to it's cyclical structure.

I have never found anything like it in other Go code. Is this very un-go? What different approach could I take?

type MyInterface interface {   SomeMethod(string)   OtherMethod(string) }  type Base struct{   B MyInterface }  func (b *Base) SomeMethod(x string) {   b.B.OtherMethod(x) }  type Extender struct {   Base }  func (b *Extender) OtherMethod(x string) {   // Do something... }  func NewExtender() *Extender {    e := Extender{}   e.Base.B = &e   return &e } 
like image 269
theduke Avatar asked Aug 24 '15 17:08

theduke


People also ask

Does Golang have inheritance?

Since Golang does not support classes, so inheritance takes place through struct embedding. We cannot directly extend structs but rather use a concept called composition where the struct is used to form other objects. So, you can say there is No Inheritance Concept in Golang.

Does Go support inheritance or generic?

Go does not support inheritance, however, it does support composition. The generic definition of composition is "put together".

Does Golang have polymorphism?

Golang is a light-Object Oriented language and supports polymorphism through interfaces only.

Can object oriented programming exist without inheritance?

Inheritance is fundamentalno inheritance, no OOP. objects, messages, and composition but no inheritance is object-based, not object-oriented.


Video Answer


2 Answers

As mentioned in people's comments, Go encourages composition over inheritance.

To address your question about reducing code duplication, you would want to use embedding.

Using the example from Effective Go linked above, you start with very narrow interfaces that only do a few things:

type Reader interface {     Read(p []byte) (n int, err error) }  type Writer interface {     Write(p []byte) (n int, err error) } 

Then you can either compose interfaces together into another interface:

// ReadWriter is the interface that combines the Reader and Writer interfaces. type ReadWriter interface {     Reader     Writer } 

It works similarly for structs, where you can compose structs that implement Reader and Writer together in another struct:

type MyReader struct {} func (r *MyReader) Read(p []byte) (n int, err error) {     // Implements Reader interface. } type MyWriter struct {} func (w *MyWriter) Write(p []byte) (n int, err error) {     // Implements Writer interface. }  // MyReadWriter stores pointers to a MyReader and a MyWriter. // It implements ReadWriter. type MyReadWriter struct {     *MyReader     *MyWriter } 

Basically, anything that implements a Reader or a Writer can be reused by composing them together in a struct, and that outer struct will automatically implement the ReadWriter interface.

This is basically doing Dependency Injection, and it's super useful for testing too.

Example from the struct code above:

func (rw *MyReadWriter) DoCrazyStuff() {     data := []byte{}     // Do stuff...     rw.Read(data)     rw.Write(data)     // You get the idea... }  func main() {     rw := &MyReadWriter{&MyReader{}, &MyWriter{}}     rw.DoCrazyStuff() } 

One thing to point out that's slightly different from other languages' composition paradigm is that the MyReadWriter struct can now act as both a Reader and a Writer. That's why in DoCrazyStuff() we do rw.Read(data) instead of rw.Reader.Read(data).

UPDATE: Fixed incorrect example.

like image 147
Addison Avatar answered Sep 19 '22 16:09

Addison


Sorry to disappoint you, but you are asking the wrong question. I had a similar problem when I started writing Go code.

You can not simply take a class hierarchy and translate it to Go code, at least not with satisfying results. Usually there is a very elegant and simple way to solve such things in Go, but to discover them, you need to think a bit differently as you are used to.

Unfortunately, your question doesn't say anything about what problem you are trying to solve. You have just described how you would like to solve it. Therefore I am a bit reluctant to give a general answer, since it will not lead to idiomatic Go code. I understand if you are disappointed by that answer, but in my opinion, that`s the most value-able answer you can get :)

like image 21
tux21b Avatar answered Sep 19 '22 16:09

tux21b