Conditionals

There are two conditional constructs in Basic Storm: the if statement and the unless statement. As with most other constructs in Basic Storm, both of them are expressions, even if they most often are used as statements.

This section focuses on the control structures themselves, and therefore only covers simple conditions. A condition may also be a weak cast, which is described in the section on type casting.

If Statements

If statements follow the same structure as in C++ and Java:

if (<condition>)
    <true branch>
[else
    <false branch>]

The if statement evaluates <condition>, which is expected to evaluate to a core:Bool. If it is true, then <true branch> is evaluated. Otherwise, <false branch> is evaluated if it exists. The two branches can be arbitrary expressions, but in many cases they are blocks that contain the code. Since if is a statement, it is possible to stack if statements as follows:

if (<condition 1>)
    <condition 1 is true>
else if (<condition 2>)
    <condition 2 is true>
else
    <otherwise>

The if statement evaluates to the value of whichever branch was taken. Since Basic Storm is statically typed, this means that the if statement must be able to compute the type of the returned value. This is done by examining the resulting type of the true- and false- branches in the if-statement and computing a common type (e.g. common base classes). If this fails, or if the false branch does not exist, then the if statement evaluates to void (i.e. nothing). Since the else if construct is just nested if-statements, this works for arbitrarily nested if statements.

For example, this allows writing code like this:

Str greeting(Str name) {
    Str name = if (name.empty) {
        "anonymous";
    } else {
    name;
    } + "!";
    return "Hello " + name;
}

Note that a semicolon (;) is necessary after the closing bracket in the if statement. This is required to let Basic Storm know when the expression ends. Furthermore, it is a good idea to use blocks when using if statements in an expression context. Otherwise one would have to use duplicate semicolons to delimit the end of the else statement and the entire expression.

Unless Statements

A unless statement is mostly equivalent to a negated if statement. That is, the two functions below are roughly equivalent.

void withIf(Bool condition) {
    if (!condition)
        return;
    // Do stuff...
}

void withUnless(Bool condition) {
    unless (condition)
        return;
    // Do stuff...
}

As can be seen from the examples above, the unless statement is designed to be useful when using early returns or guard clauses to avoid deeply nested if statements. In many languages it would be unnecessary to have a special construct for this concept. However, since Basic Storm supports weak casts that may fail, the language needs to be aware of what variables should be accessible.

To illustrate this design, consider the function getDefault below. It takes a Maybe<Int> as a parameter. Since Maybe<Int> represents a value that might be null, it is necessary to convert it into a regular Int by checking it using a weak cast (explained in detail later). We can implement the function in two ways, one with if, and the other with unless:

Int getDefault(Maybe<Int> check, Int default) {
    if (check) {
        // The weak cast above creates a new variable in this
        // scope: "Int check", that we can access.
        return check;
    }

    // Here, we can not access the "Int check" created
    // above, since the original value might have been null.
    return default;
}
Int getDefault(Maybe<Int> check, Int default) {
    unless (check) {
        // Here, the 'check' refers to the parameter
        // which has the type 'Maybe<Int>'.
        return default;
    }

    // Since the check in the 'unless' statement did not
    // fail, we now have a "Int check" variable that we
    // can access:
    return check;
}

The two versions are equivalent in this case. However, since it is not possible to negate a weak cast with the ! operator, we need to structure the code differently. This is the key reason for the existence of the unless statement. As we see from this example, the unless statements requires that the block after it either returns or throws an exception. Otherwise, Basic Storm can not safely assume that check is non-null after the unless statement, and it would not be able to safely provide a way to access the integer variable inside check.