Abstract Class reinvented

Go lang tries to distance itself from object-oriented terminology, at the same time it can give you all object-oriented programming flavors and benefits.
For instance,

  1. C++ or Java classes are called a struct,
  2. A class methods are called receivers.
  3. Inheritance is called embedding

In this post, however, I will focus on Abstract Class functionality. It can be helpful in any case when there is a need for building default or high-level functionality, leaving specialized implementation details to subclasses.

Let start with the classic object oriented animal example.

Before looking into implementation let me explain how embedding works. When embedding a type, the methods and fields of that type become part of the outer type, but when invoked or access them, an inner type is used not the outer one.

In the first animal implementation attempt I am going to use anonymous struct embedding.

First attempt

In this scenario, I have created an animal type that provided default implementations for MakeSound() and Sound() methods. On top of that I want the “sound” method act like an abstract method, so firstly I have added sanity check with panic to check it is never called from Animal type directly; secondly, I want Cat and Dog types to override it.

After running the program we would see:

panic: This is abstract method - please provide implementation

When we call a method MakeSound on Cat struct which was not directly defined but embedded we actually called it on Animal type as if we called c.Animal.MakeSound(). From that point on, any subsequent calls will use Animal not Cat type.

In the second attempt, I will define Animal interface and abstract Animal type which embeds Animal interface. This will allow routing any calls from abstract Animal type back to specific implementation of the Animal interface.

Second attempt

The second attempt provided a final solution which functionally is very close to abstract class type. Let’s scrutinize similarity with Java:
1. an abstract class can have an incomplete or no implementation,
2. an abstract class can not be directly instantiated.

In our final solution, abstractAnimal type provided the only partial implementation of the Animal interface and also it is not alone assignable to Animal type.

A specialized animal type like Cat inherits partial implementation from embedded abstract type and provide remaining methods required by an Animal interface.

This is pretty match how an abstract class works in other languages.

One final note, for simplicity I have use main package to allow you play with code in the playground, in real word it is good idea to create dedicated package for an interfaces, abstract class and types providing complete implementation.