# Types and Type Composition

**Work In Progress**

Work on this post is underway... It will be done "soon..."

We need to think of our types bottom-up. We need to thoughtfully and purposefully design our types to mirror our business domain. Types should only allow correct values. This of course comes at a cost, and we need to decide consciously where and how are we willing to pay that cost, if we want to.

I start with a TL;DR, just an example of how to create sum types, product types and ADTs. Then I explain an alternative way of looking at types and what does it mean to build from the bottom up. Then you will find in more details how to compose types from existing types. What are the different types of type composition? Finally, we will look at ways to restrict primary data types at compile time.

- TL;DR
- Types as Set of Terms (group of values)
- Building Types From The Bottom-Up
- Type Composition
- Resources

### TL;DR

- Create Sum Types
- Create Product Types
- Create ADT

### Types as Set of Terms (group of values)

We can define a type as sets of terms, think of a term as a possible value. For an example the type `boolean`

has two terms `true`

and `false`

. Those are the only valid terms for that type. The `boolean`

type is said to have a finite set of terms. The type `char`

has finite set of terms, which are the set of unicode characters. `natural numbers`

on the other hand is an infinite set of terms.Types include only valid terms. So, for the type `boolean`

the term `word`

is not valid.

A good question here is, what about the billion dollars mistake? What about `null`

? Scala unfortunately inherited `null`

from Java, a mistake that Kotlin managed to avoid. But for our purposes we will ignore the existence of null. In Scala we tend to avoid using null all together and wrap external, potentially nullable, dependencies with `Option`

.

### Building Types From The Bottom-Up

When we usually write code we use the most appropriate data type to represent a value. For an example `Int`

or `String`

to represent HTTP response codes. There is a flow in that approach. If we use `Int`

, we can set the value to `0`

which is not a valid value. If we use a `String`

, it is even worse we can set it to `Hello`

which again is not valid. A good alternative is to declare a new data type that could be represented by an `enum`

in some languages. If we only expect two values, either `200`

or `404`

, then these should be the only two values in our `enum`

. This eliminated a whole set of potential bugs.

The compiler will not allow us to use an invalid term. Using an appropriate IDE, we will get a wiggly red line informing us that we are using an inappropriate term. Yes, one can test for these sorts of things, but that means, we need to run all our tests, every time we make a change.

Testing is a poor substitute for proof. Using an `enum`

in the above example turns `val result: HttpCode = HttpCode.Ok`

into a proof, because the compiler will not let you write `val result: HttpCode = "hello"`

. These kinds of problems will only occur on system boundaries and will be handled in the proper place.

The best data type is the data type is defined as a set of only correct terms. It is a paradigm shift of sorts. We need to think about our domain or business values as a set of only correct terms. The question is, can we do that? and if we can, how much effort would it take? The answer as with everything in our line of business, it depends! How important is that phone number for you? Is it important enough to define a data type `Digit`

that has values `Zero...Nine`

then create an array of eight `Digit`

s? Or is this an overkill?

### Type Composition

There are three ways we can compose types, sum composition, product composition and mixing both in what is called algebraic data types or ADT.

#### Sum composition:

Let’s define a type `WeekendDay`

as a sum type, it can be one of two values. `Saturday`

and `Sunday`

. We can concisely express that by writing `WeekendDay: {Saturday, Sunday}`

.

Let’s say we have another data type `WorkDay: {Monday, Tuesday, Wednesday, Thursday, Friday`

.

```
object Days{
sealed trait WeekendDay
case object Saturday extends WeekendDay
case object Sunday extends WeekendDay
sealed trait WorkDay
case object Monday extends WorkDay
case object Tuesday extends WorkDay
case object Wednesday extends WorkDay
case object Thursday extends WorkDay
case object Friday extends WorkDay
}
```

We can now define a new Sum type `WeekDay = WeekendDay + WorkDay = {Monday, ..., Sunday}`

. In the current version of Scala `2.x`

we can’t create a sum type of already existing sum types. As a work around we will create `WeekDay = WeekendDay + WorkDay = {WeekendDay: {Saturday, Sunday}, WorkDay: {Monday, Tuesday, Wednesday, Thursday, Friday}`

We wil basically create a new sum type that contains two terms, each is a wrapper around one of our existing terms.

```
sealed trait WeekDay
object WeekDay {
case class WeekendDay(day: Days.WeekendDay) extends WeekDay
case class WorkDay(day: Days.WorkDay) extends WeekDay
}
val day: WeekDay = WeekDay.WorkDay(Days.Friday)
day match {
case WeekDay.WorkDay(Days.Friday) => // do something
case WeekDay.WeekendDay(Days.Saturday) => // do something
}
```

It is important to know that the number of terms of the new type is the sum of the number of terms in each type.

```
|WeekendDay| = 2
|WorkDay| = 5
|WeekDay| = |WeekendDay + WorkDay| = |WeekendDay| + |WorkDay| = 2 + 5 = 7
```

Generally, for any two types `A`

and `B`

```
A: {a1, a2}
B: {b1}
A + B = {Left_a1, Left_a2, Right_b1} // It keeps track of where they come from
|A + B| = |A| + |B| = 3
A + A = {Left_a1, Left_a2, Right_a1, Right_a2}
|A + A| = 4
```

Two ways:

- Either
- Sealed Trait sum requires a finite number of terms (vs number of values which is ok to be infinite)

#### Product composition:

Product composition is the type of composition present in most object oriented programming languages. When we declare a class or data structure `Person`

that has a name of type `String`

and an age of type `Int`

, we have composed a new type `Person`

that is a product of `String`

and `Int`

. We need both name and age to define that person. Remember, `null`

is not allowed.

Let’s formalize this a bit, for type `A`

that has values `a1`

and `a2`

which can be written as `A: {a1, a2}`

and type `B: {b1}`

, we can create a new product type `A * B = { {a1, b1}, {a2, b1}}`

. You can think of that as the *cartesian* product of the two sets of terms. The size of `A`

is `2`

, which can be written as `|A| = 2`

and similarly `|B| = 1`

. The size of the new type is the product of the sizes of `A`

and `B`

. `|A * B| = 2 * 1 = 2`

.

If it makes it easier think of it as a graph where `A`

represents an axis and `B`

represents the other. We need the product of `A`

and `B`

to find a point on that graph. The product or the point can be found by one value from `A`

and `B`

for an example `(a1, b1)`

.

#### ADT

#### Notes

- Using string to represent email/URL, etc. is not correct since it will have a lot of invalid values
- We need to tell the compiler what is valid and not valid, and in that case our code becomes a proof.