# 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).