# Type-oriented programming/Printable version

Type-oriented programming

The current, editable version of this book is available in Wikibooks, the open-content textbooks collection, at
https://en.wikibooks.org/wiki/Type-oriented_programming

Permission is granted to copy, distribute, and/or modify this document under the terms of the Creative Commons Attribution-ShareAlike 3.0 License.

# Types and properties

Types can be viewed of bundles of properties and functions operating on them. Such functions are conventionally called methods. Here’s an example of a simple type:

```type Person {
property name String
property age Int
}
```

This type declaration states that the `Person` type has two properties. An instance of this type can be created using a `new` statement:

```var p = new Person {
name = "Jane",
age = 18
}
```

The properties of a type’s instance can be accessed via the dot operator, for example:

```return p.name
```

NB: The pseudocode can be tried out using the Funcy app, which can be downloaded for free from Apple’s App Store (iOS/macOS), Google Play (Android) or Amazon Appstore. The code to be executed must be placed in a `main {}` block. The example above can be tried out by running the following code:

```type Person {
property name String
property age Int
}

main {
var p = new Person {
name = "Jane",
age = 18
}
return p.name
}
```

# Restricted properties

While subtyping is often ampliative, that is, a subtype contains all the properties of its supertype(s), it’s often useful to remove an inherited property from a subtype. For example, a complex has a real part and an imaginary part. Every real number is also a complex number but its imaginary part is always equal to zero so we don’t want this property to take up space in the instances. However we can’t remove the imaginary part altogether because it might be used by code working with complex numbers. What one can do is assign the property a fixed value:

```type Complex {
property real Float
property imag Float

func _add(x Complex) Complex {
return new Complex {
real=self.real+x.real,
imag=self.imag+x.imag
}
}

func _mul(x Complex) Complex {
return new Complex {
real=self.real*x.real-self.imag*x.imag,
imag=self.real*x.imag+self.imag*x.real
}
}

func description() String {
return self.real.description() + "+" + self.imag.description() + "i"
}
}

type Real : Complex {
restrict imag Float = 0.0
}

main {
var x = new Complex { real=2.0, imag=3.0 }
var y = new Real { real=2.0 }
return (x*y).description()
}
```

Note that the `Real` type now has only one stored property but the methods in the `Complex` type can still be used with the subtype.

NB: The pseudocode can be tried out using the Funcy app, which can be downloaded for free from Apple’s App Store (iOS/macOS), Google Play (Android) or Amazon Appstore. The code to be executed must be placed in a `main {}` block.

# Self at the type level

Just like the `self` variable refers contextually to the instance in whose method it’s used, the `Self` type variable contextually refers to the type. Let’s have a look at a simple example:

```type A {
sfunc create() Self {
return new Self
}
}

type B : A {}

main {
var obj = \$B.create()
return obj
}
```

The `create` method’s return type is `Self` so in the example above it refers to the `B` type because we called the type method using `\$B.create()`.

Using `Self` gives the type system considerable power since it squares well with type operators, as illustrated by the following example:

```type Maybe[T] {
property val T

func description() String {
return self.val.isNil() ? "none" : self.val.description()
}

func map[U](f Func[T,U]) Self[U] {
return new Self[U] {
val = self.val.isNil() ? nil : f(self.val)
}
}
}

main {
var x = new Maybe[Int] { val=3 }
var y = x.map[Float](\(x Int) Float . x.asFloat())
return y.description() + " " + y.typeName()
}
```

Note that the `map` method has a type argument and how `new Self[U]` is used. In this case `Self` is a contextual type operator.

NB: The pseudocode can be tried out using the Funcy app, which can be downloaded for free from Apple’s App Store (iOS/macOS), Google Play (Android) or Amazon Appstore. The code to be executed must be placed in a `main {}` block.

# Type variance

Consider the following type hierarchy:

```type A {}

type B : A {}

type F[T] {}
```

Without type arguments, `F` is a type operator while `F[A]` and `F[B]` are proper types. In general, neither is a subtype of the other. However it may sometimes make sense for them to be in a subtype relation depending on the hierarchy of their argument(s). If we declare `F` as follows

```type F[cov T] {}
```

then `F[B]` will be a subtype of `F[A]` because `B` is a subtype of `A`. Conversely, if we declare `F` as

```type F[con T] {}
```

then `F[A]` will be a subtype of `F[B]`. In the former case, we say that `F` is covariant in its type argument whereas in the latter case its contravariant (since the hierarchy is reversed).

A real-world example of type variance are function types. When we expect a function whose return type is `A` (that is, of type `Func[A]`), we can always use a function of type `Func[B]` in its stead. On the other hand, when we expect a function whose argument is of type `B` (that is, of type `Func[B,X]`, we can always use a function of type `Func[A,X]` in its stead. In sum, function types are covariant in their return type and contravariant in their arguments’ types.

NB: The pseudocode can be tried out using the Funcy app, which can be downloaded for free from Apple’s App Store (iOS/macOS), Google Play (Android) or Amazon Appstore. The code to be executed must be placed in a `main {}` block.

# Bounded type arguments

Consider the following code:

```type Equatable {
func equals(x Any) Bool
}

type Complex : Equatable {
property real Float
property imag Float

func equals(x Any) Bool {
if x is Complex then {
var x = x as Complex
return self.real == x.real & self.imag == x.imag
}
return false
}
}

type Pair[T] {
property first T
property second T
}

main {
var x = new Complex { real=2.0, imag=3.0 }
var y = new Complex { real=2.0, imag=3.0 }
return x.equals(y)
}
```

We now want to implement the `equals` method also for `Pair`:

```func equals(p Pair[T]) Bool {
return self.first.equals(p.first) & self.second.equals(p.second)
}
```

Note, however, that this code won’t compile since the compiler can’t be sure that `T` represents an equatable type. We need to change the declaration of `Pair` to

```type Pair[T:Equatable] { ... }
```

Now it’s ensured that `T` is equatable and we can check pairs for equality:

```main {
var x = new Complex { real=2.0, imag=3.0 }
var y = new Complex { real=2.0, imag=4.0 }
var p1 = new Pair[Complex] { first=x, second=y }
var p2 = new Pair[Complex] { first=x, second=y }
return p1.equals(p2)
}
```

Here, the `T` type argument is called bounded since there’s a type constraint placed on it.

NB: The pseudocode can be tried out using the Funcy app, which can be downloaded for free from Apple’s App Store (iOS/macOS), Google Play (Android) or Amazon Appstore. The code to be executed must be placed in a `main {}` block.

# Functors

A functor is a type operator equipped with a `map` method declared as follows:

```type Functor[T] {
func map[U](f Func[T,U]) Self[U]
}
```

The `map` method must satisfy some formal requirements that we ignore here for now. The important point is that `map` takes a function of type `Func[T,U]` (where `U` is a type argument of the method) and returns an instance of type `Self[U]`, that is, the same functor possibly with a different type argument. You’ve already met the `Maybe` functor:

```type Maybe[T] : Functor[T] {
property val T

func map[U](f Func[T,U]) Self[U] {
return new Self[U] {
val = self.val.isNil() ? nil : f(self.val)
}
}

func description() String {
return self.val.isNil() ? "none" : self.val.description()
}
}
```

In the next section, we’ll use `Maybe` to explain what a monad is and how a generic `Monad` type can be implemented.

NB: The pseudocode can be tried out using the Funcy app, which can be downloaded for free from Apple’s App Store (iOS/macOS), Google Play (Android) or Amazon Appstore. The code to be executed must be placed in a `main {}` block.