I'm a Python developer, trying to learn Go. Currently I'm trying to refactor my first small project, but I am not too sure how to share a method between structs.
Long story short, how would you do something like this Python code in Go?
class Super(object):
def CommonMethod(self):
print 'I am the common method.'
class One(Super):
def MethodOne(self):
self.CommonMethod()
print 'I am method one.'
class Two(Super):
def MethodTwo(self):
self.CommonMethod()
print 'I am method two.'
one = One()
one.MethodOne()
two = Two()
two.MethodTwo()
TL;DR
In Go methods aren't just magically inherited with subclassing as you would do in other languages like Python or Java. You can define interfaces and using embedding but you'll have to implement the methods you need for each type. Of course you can just call the method of the embedded from the outer method, however be careful that any changes will occur to the inner object and not the outer one.
From the docs:
There's an important way in which embedding differs from subclassing. When we embed a type, the methods of that type become methods of the outer type, but when they are invoked the receiver of the method is the inner type, not the outer one. In our example, when the
Read
method of abufio.ReadWriter
is invoked, it has exactly the same effect as the forwarding method written out above; the receiver is the reader field of theReadWriter
, not theReadWriter
itself.
Some more info
Here's some references from the docs:
http://golang.org/doc/faq#Is_Go_an_object-oriented_language
Is Go an object-oriented language?
Yes and no. Although Go has types and methods and allows an object-oriented style of programming, there is no type hierarchy. The concept of “interface” in Go provides a different approach that we believe is easy to use and in some ways more general. There are also ways to embed types in other types to provide something analogous—but not identical—to subclassing.
So, you can have interfaces that define what should be implemented in a type but you'll have to implement those methods for each type.
One convenience you have is Embedding:
http://golang.org/doc/effective_go.html#embedding
Go does not provide the typical, type-driven notion of subclassing, but it does have the ability to “borrow” pieces of an implementation by embedding types within a struct or interface.
Interface embedding is very simple. We've mentioned the
io.Reader
andio.Writer
interfaces before; here are their definitions.
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
The io package also exports several other interfaces that specify objects that can implement several such methods. For instance, there is
io.ReadWriter
, an interface containing bothRead
andWrite
. We could specifyio.ReadWriter
by listing the two methods explicitly, but it's easier and more evocative to embed the two interfaces to form the new one, like this:
// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
Reader
Writer
}
Based on twotwotwo's comment on my question, I came up with the following solution on Go:
Go playground link: http://play.golang.org/p/JtPAON93PO
type Super struct{}
type One struct {
Super *Super
}
type Two struct {
Super *Super
}
func (s *Super) CommonMethod() {
fmt.Println("I am the common method.")
}
func (o *One) MethodOne() {
o.Super.CommonMethod()
fmt.Println("I am method one.")
}
func (t *Two) MethodTwo() {
t.Super.CommonMethod()
fmt.Println("I am method two.")
}
Note: a recent (today Nov 18th 2014) article called "Subclassing in Go" illustrates some techniques for mimicking behaviour of “oo” languages like java or python in go.
While composition is the norm, if you need a "Parent
" type to resolve a call to a method at runtime, you would need said Parent
type to have a reference to an interface.
Note that this doesn't provide "true" inheritance though (as I explained in "Function Over Loading in GO using interfaces").
For more see "Inheritance Semantics in Go".
type Person interface {
close() // define an interface to lookup methods on
flush()
}
type Parent struct {
self Person // retain reference to self for dynamic dispatch
}
func (p *Parent) flush() {
fmt.Println("parent flush")
}
func (p *Parent) close() {
p.self.flush() // call the flush method of whatever the child is.
fmt.Println("close")
}
That way, you can "subclass" parent with a Child type (embedding Parent, and its self
interface reference):
type Child struct {
Parent
}
func (c *Child) flush() {
c.Parent.flush()
fmt.Println("child flush")
}
That means if you create a Child instance and put that instance in "self":
x := new(Child)
x.self = x
Then a call to x.close()
would print:
parent flush
child flush
close