The style of the Go language is quite unique. Compared to the traditional object-oriented mechanisms in languages like C++ and Java, Go’s approach is very different. Go supports classes but does not support inheritance or virtual functions (abstract methods). Furthermore, Go has discarded the concept of constructors.
Inheritance
Although Go is opposed to inheritance, it can achieve similar functionality through other means. Inheritance in Go can be simulated through composition, known as anonymous composition. In the following example, the class Foo inherits from the class Base:
type Base struct {
Name string
}
type Foo struct {
Base
Desc string
}By defining an anonymous member of type Base within the Foo class, Foo acquires all members of Base, meaning Name becomes a member of Foo.
The advantage of this inheritance style is that there is no need to explicitly use inheritance keywords (such as extends in Java), and there is no need to design a complex inheritance hierarchy (which is generally quite difficult). The disadvantage is that the Foo class needs to be aware of all members of the Base class because when creating a Foo object, the inherited members must be initialized:
foo := Foo{Name:"Jack", Desc:"Foo"}Interfaces
Interfaces in Go are “non-intrusive.” When implementing a class, you do not need to derive it from an interface. As long as a class implements all the methods defined in an interface, it is considered to have implemented that interface. An instance of that class can then be assigned to a variable of the interface type.
The benefit of this interface mechanism is that there is no need to establish an inheritance hierarchy. A class only needs to implement the methods it requires. Interfaces can be defined on-demand at the time of use without prior planning.
Polymorphism
In traditional object-oriented languages, the implementation of polymorphism relies on inheritance. So how is polymorphism implemented in Go, which lacks an inheritance mechanism? In practice, polymorphism in Go is primarily manifested through classes that implement the same interface. Consider the following example:
type I interface {
sayHello()
}
type Foo struct {
name string
}
type Bar struct {
name string
}
func (foo *Foo) sayHello() {
fmt.Println("hello", foo.name)
}
func (bar *Bar) sayHello() {
fmt.Println("hello", bar.name)
}
func main() {
var o1 I = Foo{"foo"}
var o2 I = Bar{"Bar"}
o1.sayHello()
o2.sayHello()
}Upon closer observation, one might find that the “polymorphism” in the above example seems redundant. Because of the nature of Go interfaces, the calls are actually made to the member methods of the Foo and Bar instances. Since only the “subclass” methods exist, it is inherently polymorphic.
In object-oriented languages, the more critical aspect is polymorphism within class inheritance. I haven’t found much documentation regarding polymorphism in Go’s class inheritance, but my view is this: polymorphism exists to allow the same parent class method to behave differently for different subclasses. However, since Go has this non-intrusive interface mechanism, there is no need to implement polymorphism within class inheritance. Subclasses do not need to share a common parent class; they only need to each possess a method with the same name. By using an interface to define this method, you can call the method on each class directly. In other words, languages like Java cannot achieve this type of polymorphism without Go’s interface functionality and must build an inheritance hierarchy to implement it. Go’s style dictates using composition more and inheritance less (or not at all), which serves as an example of how a language influences programming style.
Differences Between Go and Java
From an object-oriented perspective, Java is a relatively thorough object-oriented language (primarily evidenced by all variables and methods residing within classes). In contrast, Go is not an object-oriented language at its core, or rather, it runs contrary to traditional object-oriented methods. Go does not support inheritance; it actually favors composition, advocating for solving problems in a clear and straightforward manner rather than through a bloated inheritance hierarchy. While Go can simulate inheritance, writing code this way would inevitably lead to very bulky code (compared to Java). Overall, the philosophies of Go and Java regarding object-oriented programming are quite different, which also leads to significant differences in syntax.
References
- Xu Shiwei et al., Go Programming, People’s Posts and Telecommunications Press
- Go Language (II) Inheritance and Overloading, http://www.cnblogs.com/xuxu8511/p/3296546.html
- How to implement polymorphism-like functionality in Go as in C++, http://www.2cto.com/kf/201502/374968.html