Liskov and type safety
Tags: typesystems, programming, types
Published: 2019-06-13 09:04:30

---
title: Liskov and type safety
published: true
tags: ["type systems", programming, types]
canonical_url: https://stitcher.io/blog/liskov-and-type-safety
---

I've been fascinated by type systems in programming languages for a while now. Recently, something clicked for me about inheritance and types.

Not only did it clarify type variance, I also understood what the Liskov substitution principle actually is about. Today, I'm going to share these insights with you.

## Prerequisites

I'll be writing pseudo code to make clear what I'm talking about. So let's make sure you know what the syntax of this pseudo code will be.

A function is defined like so.

```
foo(T) : void

bar(S) : T
```

First comes the function name, second the argument list with types as parameters, and finally the return type. When a function returns nothing, it's indicated as `void`.

A function can extend another function, as can types. Inheritance is defined like so.

```
bar > baz(S) : T

T > S
```

In this example, `baz` extends `bar`, and `S` is a subtype of `T`. The last step is being able to invoke the function, which is done like so.

```
foo(T)

a = bar(S)
```

Once again: it's all pseudo code and I'll use it to show what types are, how they can and cannot be defined in combination with inheritance, and how this results in type-safe systems.

## Liskov substitution principle

Let's look at the official definition of the LSP.

> If `S` is a subtype of `T`, then objects of type `T` may be replaced with objects of type `S`  
> —[Wikipedia](https://en.wikipedia.org/wiki/Liskov_substitution_principle)

Instead of using `S` and `T`, I'll be using more concrete types in my examples.

```
Organism > Animal > Cat
```

These are the three types we'll be working with. Liskov tells us that wherever objects of type `Organism` appear in our code, they must be replaceable by subtypes like `Animal` or `Cat`.

Let's say there's a function used to `feed` an `Organism`.

```
feed(Organism) : void
```

It must be possible to call it like so:

```
feed(Animal)
feed(Cat)
```

Try to think of function definition as a contract, a promise; for the programmer to be used. The contract states:

> Given an object of the type `Organism`, I'll be able to execute and `feed` that `Organism`.

Because `Animal` and `Cat` are subtypes of `Organism`, the LSP states that this function should also work when one of these subtypes are used.

This brings us to one of the key properties of inheritance. If Liskov states that objects of type `Organism` must be replaceable by objects of type `Animal`, it means that `Animal` may not change the expectations we have of `Organism`.`Animal` may extend `Organism`, meaning it may _add_ functionality, but `Animal` may not change the certainties given by `Organism`.

This is where many OO programmers make mistakes. They see inheritance more like "re-using parts of the parent type, and overriding other parts in the sub-type", rather than extending the behaviour defined by its parent. This is what the LSP guards against.


Continue reading on [https://stitcher.io/blog/liskov-and-type-safety#benefits-of-the-lsp](https://stitcher.io/blog/liskov-and-type-safety#benefits-of-the-lsp)