Maybe and Null
    Variables may not contain the value null by default. This is true even for class- and actor types
    that are represented by a reference that could technically contain null. Instead, Basic Storm
    requires using the type Maybe<T>, or its shorthand T?, to represent a type that may contain
    either the type T or the value null. Since Maybe<T> is a separate type, it is possible to
    create Maybe<T> for all T in the system, including types that are not reference-types.
    The main benefit of this approach is that the language is aware of all variables that may be null,
    and can require the programmer to explicitly check them at appropriate points. In particular, the
    class Maybe<T> only contains members for checking if an element is present (empty or any).
    There is no way to access the element inside the Maybe type.
    Instead, elements in a Maybe<T>-type must first be casted into a non-maybe type, T, by using a
    weak cast. Weak casts are described in full in the section on type
    conversions, but a brief example is provided below for completeness.
    To check whether a Maybe type contains an object, one can simply use the any or empty members
    of the Maybe type as follows:
void fn(Int? x) { if (x.any) { // 'x' was not null. // We can still not access its contents... } }
Using a weak cast, we are also able to access the element if it was not null:
void fn(Int? x) { if (v = x) { // 'x' was not null. print(v.toS); // We can access it now! } }
    In this particular case, we could simply write if (x), and use x in the body of the if
    statement. More details are available in the type conversions section.
    Basic Storm is able to automatically convert from non-Maybe types into Maybe types in many
    cases. For example, the following function will work as expected:
Str? fn() { "fn"; // Automatically casted to Str? }
    In some situations, it might be necessary to manually cast to Maybe<T>. This can be done either by
    calling the Maybe<T> constructor, or by using the ? prefix operator. One example where automatic
    casts fail currently in is inside if-statements:
Str? fun(Bool c) { if (c) { fn(); // calls 'fn' from the above example. } else { "fun"; } }
    The code above will fail to compile since the if statement does not consider Maybe<Str> and
    Str to be related. The issue can be solved either by explicitly returning the results with the
    return statement. It might also be solved by an explicit cast in the second case:
Str? fun(Bool c) { if (c) { fn(); } else { ?"fun"; // or Str?("fun") } }
Null
    Variables of the type Maybe<T> are initialized to null. Basic Storm also provides the keyword
    null as a shorthand for Maybe<T>() or T?(). The null keyword is a bit special. Since it is
    not possible to infer the exact type of a null value (i.e. the type is Maybe<T> for any T),
    it needs to be used in a context where Basic Storm can infer the type. For example, the following
    situation works as expected since the function needs to produce a Maybe<Int> as a result:
Int? fn() { return null; }
However, the following would produce an error, since we asked Basic Storm to infer the type of the variable:
void fn() { var x = null; // Will prouce an error. }
Representation of Maybe<T>
    The Maybe<T> has two implementations, depending on whether T is a value, or if it is a class or
    an actor. For classes and actors, Maybe<T> simply contains a reference to the object. In contrast
    to other references in the system, the one stored inside Maybe<T> might be null. For value
    types, Maybe<T> stores a copy of the value. After the value, it stores a boolean value that
    indicates whether or not it represents null. As such, Maybe<T> for classes does not incur any
    extra memory, while Maybe<T> for integers incurs an extra boolean of overhead (which typically
    consumes 4 or 8 bytes due to alignment requirements).
