Optional

There are just two kinds of Booleans: True and False. In programming, there are many cases where there are two kinds of an abstract idea. Another very popular case is Optionals: An optional represents the presence or absence of a certain unit of data. We can think of optionals as a kind of boolean where True holds some extra information.

You should now be able to read the code below and understand it.

Opt[T]: {
  .match[R](m: OptMatch[T,R]): R -> m.empty
  }
OptMatch[T,R]: {
  .empty: R;
  .some(t: T): R;
  }
Opts: {
  #[T](t: T): Opt[T] -> { .match m -> m.some(t) }
  }

The code below can be used as follows:

Opts#bob //(1) Bob is here

Opt[Person] //(2) no one is here

.age(p: Opt[Person]): Nat-> p.match{  //(3) age or zero
  .empty    -> 0;
  .some p'  -> p'.age; //Yes, p' is a valid parameter name
  }

Here we show (1) how to make an optional containing a Person, (2) an empty optional and (3) how to make a method using an optional person.

Optionals and booleans are used a lot in Fearless programming. Optionals and booleans in the Fearless standard library are conceptually identical to the ones we have shown here. There are a few minor differences because of some language features that we have not seen yet; and a few extra utility methods.

Later, we will show you the exact implementation as in the Fearless standard library, but the implementation we have just seen is a very good mental model to conceptualise those two types.

To get more comfortable with the various shortcuts Fearless offer, consider the code below, that works identically to the code shown above but uses shortcuts and less indentation to be more compact:

Opt[T]: { .match[R](m: OptMatch[T,R]): R -> m.empty }
OptMatch[T,R]: { .empty: R; .some(t: T): R; }
Opts: { #[T](t: T): Opt[T] -> { ::.some t } }
Opts#bob //(1) Bob is here

Opt[Person] //(2) no one is here

.age(p: Opt[Person]): Nat-> p.match{  //(3) age or zero
  0;
  ::.age;
  }