Type Thinking 🤔 P2 - Typeclass
Tags: typescript, rust, haskell, functional
Published: 2020-05-08 15:39:19

In this post I shortly compare:
- Haskell *Typeclass*
- Rust *Trait*
- Typescript type constraints 


### Demystifying some big words (wikipedia definitions):

- *Polymorphism* - (many forms) "Polymorphism is the provision of a single interface to entities of different types"

I remember facing "polymorphism" when I just started to learn Java as a first OOP lang (~8 years ago). 
The teacher taught us that one of the basics principles of an OOP lang is "*polymorphism*". 
Whenever I hear of it I think of the famous animal example. having "Animal" class which the "Dog" and "Cat" inherit from and I can iterate a collection of Animals and invoke the "makeSound()" function they all implement cause they all of the same type (object) - "Animal".

But If being honest I don't remember the last time I used inheritance (even the prototype kind..) I usually define a structure type by an interface and defines another "behavioural" interface containing the methods I need to implement. (a matter of taste? Or a better segregation...).

  
- *Ad hoc polymorphism* or just overloading: "Defines a common interface for an arbitrary set of individually specified types". on top of that we have functions overloading - the ability to create multiple functions of the same name with different implementations (handled by the compiler).

- *Parametric polymorphism* "A way to make a language more expressive, while still maintaining full static type-safety" (Generics..)

- *Dynamic Dispatch* - The process of selecting which implementation of a polymorphic operation (method or function) to call at run time.

### Definitions: 

| TypeClass  |   Trait |  Interface  |
|---|---|---|
| [A type system construct that supports ad hoc polymorphism. This is achieved by adding constraints to type variables in parametrically polymorphic types.](https://en.wikipedia.org/wiki/Type_class) If a type is a part of a typeclass it should implement the behavior described on that typeclass.| [A trait is a language feature that tells the Rust compiler about functionality a type must provide](https://doc.rust-lang.org/1.8.0/book/traits.html) |   We use an *interface* to define a shape and we use *Generics* constraints for saying that a certain behaviour (or an attribute) is required by a type. |

### Examples:

Haskell: 
Following example is from: [learnyouahaskell] (http://learnyouahaskell.com/making-our-own-types-and-typeclasses)
``` haskell
data Person = Person { firstName :: String  
                     , lastName :: String  
                     , age :: Int  
                     } deriving (Eq) 

let adRock = Person {firstName = "Adam", lastName = "Horovitz", age = 41}  
let mca = Person {firstName = "Adam", lastName = "Yauch", age = 44}  
-- mca == adRock will be false

```
I'm far of being an haskell developer but it seem to fit the typeclass definition, there's a class Eq, it contains "==" and "/=" functions, 
deriving (Eq) tells the compiler to generate instance of the Eq class for the Person type, this way it implements / has the "==" "/=" operators. 

Rust:

``` rust
trait NoisyAnimal {
    fn make_noise<'staic>(&self) -> &'staic str;
}
struct Cat{}
impl NoisyAnimal for Cat {
    fn make_noise<'staic>(&self) -> &'staic str {
        "meow"
    }
}

struct Dog{}
impl NoisyAnimal for Dog {
    fn make_noise<'staic>(&self) -> &'staic str {
        "woof"
    }
}

fn make_noises(animals: Vec<Box<dyn NoisyAnimal>>) {
                        //       ----- trait object
    for animal in animals.iter() {
        println!("{}", animal.make_noise());
    }
}

fn make_noises_with_constraints<T: NoisyAnimal>(animal: T) {
    println!("{}", animal.make_noise());
}

pub fn call_make_noises() {
    make_noises_with_constraints(Dog{});

    let animals: Vec<Box<dyn NoisyAnimal>> = vec![
        Box::new(Dog{}),
        Box::new(Cat{}),
    ];
    make_noises(animals);
}
```
*Struct* is a type that is composed of other types. (in Typescript we model in an *interface*). In the above example we're implementing the trait obj functionality to 2 structs Cat & Dog. 
The make_noises fn iterates a vector of types that implements the trait object (dynamic dispatch) - pretty cool :D.
I also created the make_noises_with_constraints() methos which demonstrates a trait constraint which is more relevant to the concepts I raised..
 
Typescript:

``` typescript

interface Instrument {
    play: () => void;
}
class Guitar implements Instrument {
    play() {}
}

class Drums implements Instrument {
    play() {}
}

function playPart  <T extends Instrument>(instruments: T[]) : void {
    for (const instrument of instruments) {
        instrument.play();
    }
}

playPart([new Guitar(), new Drums()]);
```
Using Generics constraints I'm not limiting the playPart() function for a single type of instruments, we can make sound of many things, e.g. a bottle of beer, so in case that bottle implements the Instrument interface, it will be playable - (which could be a better name actually :P ).

Cheers,
Liron.