Find your Types!

Today, let's talk about types

About static types, not the others

Let's have some fun

And who knows? Maybe you will

Jordane Grenat – @JoGrenat

Picture from congerdesign

Picture from Björn Larsson, www.bjornlarsson.se

Types

const myCard = {
  value: 2,
  color: 'heart'
};
const myCard = {
  value: 10,
  color: 'spade'
};
const myCard = {
  value: 11,
  color: 'club'
};
const myCard = {
  value: ?,
  color: 'club'
};
interface Card {
  value: number;
  color: string;
}

11 =  ?

const myCard = {
  value: 83,
  color: 'club'
};
const myCard = {
  value: 3,
  color: 'green'
};
const myCard = {
  value: -1.6,
  color: ''
};

A type is the
shape of a value

A type is a set of possible values

Number

3.17

-6

0

98438I9

...

Bool

True

False

Cardinality = number of possible values

(value, color)

number

string

X

(value, color)

13

4

X

52


public enum Color {
  HEART, SPADE, CLUB, DIAMOND;
};

public enum Value {
  ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN,
  EIGHT, NINE, TEN, JACK, QUEEN, KING;
};

public class Card {
  public Value value;
  public Color color;
}
public enum Color {
  HEART, SPADE, CLUB, DIAMOND;
};
public enum Color {
  HEART, SPADE, CLUB, DIAMOND;
};

public enum Value {
  ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN,
  EIGHT, NINE, TEN, JACK, QUEEN, KING;
};

13

4

52

52 cartes

+ 2 jokers

54

public enum Color {
  HEART, SPADE, CLUB, DIAMOND, 
  BLACK, RED;
};

public enum Value {
  ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN,
  EIGHT, NINE, TEN, JACK, QUEEN, KING,
  JOKER;
};

public class Card {
  public Value value;
  public Color color;
}

14

6

84

30

14 x 6 = 84

13 x 4 + = 54

public class Card {
  public Value value;
  public Color color;
}

A card is a value AND a color

public enum Color {
  HEART, SPADE, CLUB, DIAMOND;
  
}
public enum Color {
  HEART, SPADE, CLUB, DIAMOND,
  NEW_COLOR;
}

4

+ 1 = 5

A color is heart OR spade OR club OR diamond                      

OR new_color

AND = multiply

OR = add

What is a Card?

A card is
    a color AND a value
    OR a red joker
    OR a black joker

public enum Card {
  SIMPLE_CARD(Value, Color),
  RED_JOKER,
  BLACK_JOKER;
}
type Card =
    SimpleCard Value Color
    | RedJoker
    | BlackJoker 

AND  = Product Type

OR  = Sum Type

BOTH  = Algebraic Data Type

public Order orderProduct(Product product, boolean withGiftWrap) {
    // ...
}

orderProduct(book, true);
public enum GiftWrap {
    NO_GIFT_WRAP, WITH_GIFT_WRAP;
}

public Order orderProduct(Product product, GiftWrap giftWrap) {
    // ...
}

orderProduct(book, WITH_GIFT_WRAP);
type Card = SimpleCard | 'Red Joker' | 'Black Joker';

interface SimpleCard {
  color: Color;
  value: Value;
}

Picture from Tristan Schmurr, flickr.com/photos/kewl/

(value, color)

13

4

X

52

null

(13 + 1) x (4 + 1) = 70

null

(13 + 1) x (4 + 1) = 52

Nullable value

Something that is a value or is nothing

OR

type MaybeString =
    Just String
    | Nothing
case myString of 
  Just value ->
    value
  Nothing -> 
    "No value"

Picture from Tristan Schmurr, flickr.com/photos/kewl/

type Maybe a =
    Just a
    | Nothing
myString : Maybe String
myString = Just "Hello"

Maybe String Maybe Int

String value = "value";
Optional<String> optional = Optional.of(value);
assertTrue(optional.isPresent());
function viewName(user: User | null) {
  if (user !== null) {
    console.log(user.name);
  }
}

with strictNullChecks

Reduce invalid inputs

try {
    Files.readAllLines(filePath, UTF_8);
} catch (IOException e) {
    // error handling
}
enum Result<T, E> {
 Ok(T),
 Err(E),
}
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error>
Try.of(() -> Files.readAllLines(filePath, UTF_8))
  .getOrElse(emptyList);

Make your function total

import {ok, fail, Result} from './result.ts';

function sendEmail(email: string, content: string)
	: Result<void, string> {
  if (!isValid(email)) {
    return fail('Invalid email');
  }
  // ... actually send the email
  return ok(void);
}
export class Email {
  private constructor(private email: string) {}
  
  static fromString(emailString: string): Result<Email, string> {
    if (isValid(emailString)) {
      return fail('Invalid email');
    }
    return ok(new Email(emailString));
  }
}
function sendEmail(email: Email, content: string): void {
  // actually send email
}
  • Restrict domain to avoid checks
  • Make your functions total
  • Explicit over implicit

Cardinality = number of possible values

card(string) =

card(number) =

card(bool) = 2

card(Unit) = 1

Unit Type

public enum Unit {  
 UNIT; 
}

Usually named ()

No information

pub fn set_permissions(&self, perm: Permissions) 
    -> Result<(), io::Error>

No arguments

myValue : Int
myValue = 13 ^ 150
myValue : () -> Int
myValue () = 13 ^ 150

myOtherValue : Int
myOtherValue = myValue () + 2

➡ Lazy evaluation

Natural integers

myValue : List ()
myValue = []

myValue2 : List ()
myValue2 = [(), ()]
List.length myValue -- 0

List.length myValue2 -- 2
type alias NaturalInt = List ()

Bottom Type

data Void
type Never = 
  JustOneMore Never
  
myValue = 
  JustOneMore (JustOneMore (...))

card(Void) = 0

Impossibility

pub fn thisCannotFail(&this) 
    -> Result<MyResult, Void>

Non-ending

pub fn thisDoesNotEnd(&this) 
    -> Void

Phantom type

type Maybe a =
    Just a
    | Nothing
type Input a
  = Value String

= Flag

type Validated = InputValidated
type NotValidated = InputNotValidated

create : String -> Input NotValidated
create value = Value value
validate : Input NotValidated -> Maybe (Input Validated)
validate (Value value) =
  if isValid value then
    Just (Value value)
  else
    Nothing
saveForm : Input Validated -> Result Error ()
myInput = create "value"

saveForm myInput
myInput = create "value"

case validate myInput of
  Just validatedInput ->
    saveForm validatedInput
  Nothing ->
    doSomethingElse

➡ Ensure workflow

type Validated = 
  InputValidated Never
  
type NotValidated = 
  InputNotValidated Never
type Validated = 
  InputValidated
  
type NotValidated = 
  InputNotValidated
type Currency a = Currency Int

type Euro = Euro Never
type UsDollar = UsDollar Never

euro : Int -> Currency Euro
euro amount = Currency amount

usDollar : Int -> Currency UsDollar
usDollar amount = Currency amount
add : Currency a -> Currency a -> Currency a

Bool

True

False

Type

Values


hand = Ace :: King :: Queen :: Jack :: Ten :: Nil

fifthCard = index 4 hand

sixthCard = index 5 hand
hand : Vect 5 Card
hand = Ace :: King :: Queen :: Jack :: Ten :: Nil

fifthCard = index 4 hand

sixthCard = index 5 hand
hand : Vect 5 Card
hand = Ace :: King :: Queen :: Jack :: Ten :: Nil

fifthCard = index 4 hand

sixthCard = index 5 hand

index : Fin n -> Vect n e -> e

Dependent types

Contraintes

Garanties

  • Moins d'états impossibles
  • Moins d'edge case
  • Moins de bugs
  • Moins de tests

Quiz Time!

function1 : a -> b


function2 : a -> a


function3 : a -> String


function4 : String -> String

0

function2 : a -> a

1

function3 : a -> String

function4 : String -> String

Plus de contraintes ≠ Moins de liberté

Thanks !

Types top !

By ereold

Types top !

  • 1,681