Improving the class inheritance

Oleg Uryutin
3 min readMar 25, 2021

It’s time to add some new useful features in good-old class inheritance in object-oriented programming.

I’ve talked about classes and objects in the previous article. A simple class has a parent and consists of members: properties and methods. Let’s stay class members for my next article and talk about inheritance.

When one class inherits another, it gets all the parent’s properties and methods and may add new members or override them. How does it work? Let’s imagine a class describing a fixed-point number. Such numbers have a fixed number of digits after (and sometimes also before) the decimal point and are useful for representing fractional values, especially in financial calculations.

class Fixed {
static const digits:Int = 4
protected var value:Int
init(value:Float) {...}
...
}

Ok. Now we can use fixed-point numbers with a fractional part of four digits. A fixed-point number stores value as an integer and the constant property ‘digits’ says where the decimal point should be:

import Fixed
class Math {
let pi:Fixed = 3.14159265 // Will be truncated to 3.1415
...
}

We have to change the class ‘Fixed’ when we need more digits in the fractional part. Let’s do it traditionally by creating a subclass with overridden property ‘digits’:

class Fixed8: Fixed {
static const digits:Int = 8
}
import Fixed8
class Math {
let pi:Fixed8 = 3.14159265
...
}

Looks good, but together with a new class, we must redeclare property ‘pi’ in our program. To eliminate this redundant work and make a program portable, we can use the first improvement of inheritance called ‘import with modification’:

import Fixed { static const digits:Int = 8 }
class Math {
let pi:Fixed = 3.14159265
...
}

Looks better, right? Our class ‘Math’ stays unchanged, but all ‘Fixed’ numbers got additional precision. It’s good when we need all fixed-point numbers with the same accuracy. We may use the second improvement of inheritance, called ‘invariant values in class’, when we need different fixed-point numbers in our program:

class Fixed<Digits:Int> {
static const digits:Int = Digits
protected var value:Int
init(value:Float) {...}
...
}

Invariant, or generic classes, are well-known. They give the ability to use variable types in strong-type programming languages. A common example is the class ‘Array’ where invariant value is a name of the class:

class Array<T> { ... }
var x: Array<Int> // Array of integer numbers

Invariant values can be not only classes but variables as well:

// "V" expected as any class name, "I" expected as "Int" or "Str"
class
Indexable<V, I as Int|Str>
// "Bits" is "Int" value expected as 8, 16, 32 or 64 only
class
Binary<Bits as 8|16|32|64>
// "Digits" is "Int" value in range 1..18
class Fixed<Digits:Int as [1..18]>

So, after the last improvement, ‘Fixed’ numbers can be declared as follows:

var pi:Fixed<8> = 3.14159265
var cost:Fixed<2> = 1000.00

We can use invariant values for conditional code generation as well. The initialization method of the class ‘Fixed’ now looks as follows:

init(value:Float) {
@invariant {
<Digits == 2> {...} // Special validation for currency values
<default> {...}
}
}

The third improvement of inheritance is ‘selective inheritance protection’. Object-oriented programming languages provide the ability to protect a class of modification. Keyword ‘final’ in class declaration makes it impossible to add or override new members in such languages as Swift, C++, and PHP.

To protect the whole class ‘Fixed’ of any modifications, we must lock it:

locked class Fixed<Digits:Int as [1..18]> { ... }

But protection may be flexible. Lock sentences allow protecting separate members of the class selectively:

// Deny function overriding and adding in a subclass
class
A locked func {...}
// Deny to add new functions to a subclass, overriding allowed
class A locked new func
// Deny overriding of initializers, addition is allowed
class A locked override init
// No new public members allowed in a subclass; overriding allowed
class
A locked new public
// No changes in public and private constants allowed
class
A locked public|private let

Summing up:

Inheritance in object-oriented programming languages can be improved by:

  1. Import with modification
  2. Invariant values in class and invariant conditional code generation
  3. Selective inheritance protection.

In my next article, I will take you on an enthralling trip around improvements in class members. Sure, you will discover a lot of enjoyable there.

--

--

Oleg Uryutin

System architect and master developer of the Aplextor