zax.io

A guide to the Zax programming language

View project on GitHub

Zax Programming Language

Flow Control

if

An if statement tests a condition and if a condition is true then code that follow executes, or if a condition is false then skips a code block and proceeds to execute code following an else statement (if present).

Flow control code blocks following an if or else condition must either continue on the following line or must be encapsulated inside a scope.

isNegativeOrGreaterThan10 : (negative : Boolean)(input : Integer) = {

    if input < 0
        return true

    if input > 10 {
        return true
    }

    return false
}

assert( !isNegativeOrGreaterThan10(5) )
assert( isNegativeOrGreaterThan10(-15) )
assert( !isNegativeOrGreaterThan10(10) )
assert( isNegativeOrGreaterThan10(11) )

This code will not compile:

isNegative final : (output: Boolean) (input : Integer) = {

    // ERROR: the condition and statement following have no separation
    if input < 0 return true

    // ERROR: the condition and statement are still not separated and this is
    // not a legal form of the `if` statement
    if input < 0; return true

    // OKAY: This example is allowed
    if input < 0 { return true }

    // OKAY: This example form is okay
    if input < 0
        return true

    // OKAY: This example form is also okay
    if input < 0 {
        return true
    }

    // the `;` operator causes the code statement that follow to be considered
    // part of the same statement at the same scope (even though they are
    // separate statements)
    if input < -1
        ++input;
        value := input * 3;
        input /= value;
        return true

    return false
}

if / else

An if and else statement can be used to run one block of code or another depending if a condition is true or false.

print final : ()(...) = {
    // ...
}

fruit := "apple"

if fruit == "apple"
    print("yummy")
else
    print("what is it?")


fruit = "durian"

if fruit == "durian" {
    print("yuck!")
    print("I know a few people who love it but I think it's noxious!")
} else
    print("oh good, not that one")

if / else if

If an if condition is false then an else statement can immediately be followed by another if statement for testing another condition dependent on a first condition being false.

print final : ()(...) = {
    // ...
}

whatsForLunch final : (mood : String)(food : String) = {

    weight : Float

    if food == "apple" {
        weight = 100
        mood = "happy"
    } else if food == "banana" {
        weight = 118
        mood = "delighted"
    } else if food = "durian" {
        weight = 226
        mood = "disgusted"
    } else if food == "potato" {
        weight = 180
        mood = "indifferent"
    }

    if weight < 150 {
        mood = mood + " and hungry"
    }

    return mood
}

print("my disposition is", whatsForLunch("apple"))
print("my disposition is", whatsForLunch("veal"))

if initialization statements and condition

An if statement can contain an initialization statement with a condition (which must be separated by a sub-statement separator ;;) followed by a code block. If a value is declared in an initialization statement then that value’s scope only exists within the context of an if or else control flow.

// a happy number is less than -5 and even, or less than -10, or divisible by 3
isHappyNumber final : (output : Boolean)(input : Integer) = {

    if positive := input * -1 ;; positive > 5
        return positive > 10 || input % 2 == 0

    return input % 3 == 0
}

assert(!isNegative(5))
assert(isNegative(-15))

This form of if statement is useful for error condition handling without a need for exceptions:

Error :: type {
    // ...
}

loadStringFromUrl final : (
    result : String,    // contents returned from url already base64 decoded
    error : Error       // an error is set when server cannot be reached
)(
    url : String        // the url to fetch the base64 encoded data
) = {
    if base64String:, resourceError: = fetchUrlAsBase64(url) ;; !resourceError {
        result = decodeBase64(base64String)
    } else
        return #, resourceError as Error

    cacheDataForLater(result)
    return result, #
}

ternary operator

A ternary operator is a lightweight if statement. A ternary operator performs a conditional test and then chooses one value or another based on a conditional test being true or false. The ternary operator is split into sections: a conditional test, followed by ?? operator, followed by result if true, followed by a sub-statement separator ;;, followed by a result if false.

a := 5
b := 10
c := 20
d := 30

// `e` is assigned to `c` if `a` is greater than `b` otherwise `e` is assigned
// to `d` all selected using the ternary `??` operator
e := a > b ?? c ;; d

// the above ternary operation is approximately equivalent to the following:
e : Integer = ???
if a > b
    e = c
else
    e = d

The ternary operator can be surrounded by () to ensure the sub-statement separator is not confused with other code that relies upon sub-statement separators.

coinFlip final : (result : Boolean)() = {
    // ...
}

random final : (result : Integer)() = {
    // ...
}

// the sub-statement separator for the ternary operator is distinct from the
// sub-statement separator for the `if` with an initialization statement
if i := (coinFlip() ?? random() ;; 10) ;; i > 0 {
    // do something ...
} else {
    // do something else ...
}

The true or false result for a ternary operator must be of exactly the same type (although they may be casted to the same type).

coinFlip final : (result : Boolean)() = {
    // ...
}

randomU32 final : (result : U32)() = {
    // ...
}

randomU16 final : (result : U16)() = {
    // ...
}

// ERROR: the ternary options are not of the same type for the `true` and
// `false` path
i := coinFlip() ?? randomU32() ;; randomU16()

// OKAY: the types are the same and thus fully compatible for both the `true`
// and `false` path
j := coinFlip() ?? randomU32() ;; randomU16() as U32

while

A while statement will repeat over a code block while a condition is true.

print final : ()(...) = {
    // ...
}

countToOneHundred final : ()(starting : Integer) = {
    // repeat until starting reaches 100
    while starting <= 100 {
        print(starting)
        ++starting
    }
}

while initialization statements and condition

A while statement will repeat over a code block while a condition is true. A while statement can contain initialization statements with a condition followed by a repeatable code block which must be separated by a sub-statement separator (;;) except for the repeatable code block. If a value is declared in an initialization statement then that value’s scope only exists within the context of a while control flow.

print final : ()(...) = {
    // ...
}

fetchNumberFromCosmos final : (output : Integer)() = {
    // ... returns cosmic number
}

countToCosmicNumber final : ()(starting : Integer) = {
    while endingNumber := fetchNumberFromCosmos() ;; starting <= endingNumber {
        print(starting)
        ++starting
    }
}

while initialization statements, condition, and post statements

A while statement will repeat over a code block while a condition is true. A while loop can contain an initialization statement, a condition, and a post loop statement followed by a repeatable code block. Each section must be separated with sub-statement separators (‘;;’) except for the repeatable code block. Variables declared in an initialization statement are scoped to an iterated loop. A post loop statement is executed after each completed repeatable code block has executed (assuming a break statement was not encountered while executing a while loop’s repeatable code block).

This code is valid:

print final : ()(...) = {
    // ...
}

countAndSkipOdds : (output : Integer)() = {
    total := 0
    while i := 0 ;; i < 100 ;; ++i {
        if i % 2 == 0 {
            ++total
            print("Counting", i)
        } else
            print("Not counting", i)
    }
    return total
}

Alternative forms using while loops:

print final : ()(...) = {
    // ...
}

doStuff final : (output : Integer)() = {
    total := 0

    // OKAY: a condition statement and repeatable code block are present but no
    // initialization or post loop statement is present
    {
        i := 0
        while i < 100 {
            if i % 2 == 0 {
                ++total
                print("Counting", i)
            } else
                print("Not counting", i)
        }
    }

    // OKAY: an initialization, condition statement, and repeatable code block
    // are present but no post loop statement is present
    while i: ;; i < 100 {
        ++i
        ++total
    }

    // OKAY: an initialization and a post loop statement are present followed by
    // a repeatable code block
    while i: ;; i < 100 ;; ++i {
        ++total
    }

    // ERROR: A sub statement separator `;;` was present indicating a post loop
    // statement should be present; this cause the repeatable code block to
    // treated as the post loop statement by the compiler, and the compiler
    // continues to attempt to locate a repeatable code block which isn't
    // present; thus the compiler will issue an error.
    while i: ;; i < 100 ;; {
        print(i)
        ++i
        ++total
    }

    // OKAY: an initialization and a post loop statement are present and a
    // an empty scope is used in place for the repeatable code block
    while i: ;; i < 100 ;; ++i {}

    // OKAY: a post loop statement is empty but present
    while i: ;; i < 100 ;; {} {
        print(i)
        ++i
        ++total
    }

    // OKAY: an initialization is present and a post loop statement is empty but
    // present; the repeatable code block is present (although it will repeat
    // forever since `i` is always `< 100`)
    while i: ;; i < 100 ;; {}
        print(i)

    // OKAY: An initialization, condition, and post loop statement are present
    // and the repeatable code block is present. The `;` operator causes
    // multiple statements to be combined together and treated as a single
    // statement at the same scope.
    while i: ;; i < 100 ;; ++i; ++total
        print(i)

    // OKAY: An initialization, condition, and post loop statements are present
    // and the repeatable code block is present. The `;` operator causes
    // multiple statements to be combined together and treated as a single
    // statement at the same scope. The repeatable code block is using the `;`
    // operator to indicate that all the loop statements are part of the same
    // statement at the same scope.
    while i: ;; i < 100 ;; ++i; ++total
        print(i);
        print(i % 10)

    // OKAY: An initialization, condition, and post loop statements are present
    // and the repeatable code block are all present. The `;` operator causes
    // multiple statements to be combined together and treated as a single
    // statement at the same scope.
    while i: ;; i < 100 ;; ++i; ++total {
        print(i)
    }

    return total
}

until

An until statement will repeat over a code block until a condition is true.

print final : ()(...) = {
    // ...
}

countToOneHundred final : ()(starting : Integer) = {
    // repeat until `starting` reaches `100`
    until starting > 100 {
        print(starting)
        ++starting
    }
}

until initialization statements and condition

An until statement will repeat over a code block until a condition is true. An until statement can contain an initialization statement with a condition followed by a repeatable code block which must be separated by a sub-statement separator (;;) except for the repeatable code block. If a value is declared in an initialization statement then that value’s scope only exists within the context of an until control flow.

print final : ()(...) = {
    // ...
}

fetchNumberFromCosmos final : (output : Integer)() = {
    // ... returns cosmic number
}

countToCosmicNumber final : ()(starting : Integer) = {
    until endingNumber := fetchNumberFromCosmos() ;; starting > endingNumber {
        print(starting)
        ++starting
    }
}

until initialization statements, condition, and post statements

An until statement will repeat over a code block until a condition is true. An until loop can contain an initialization statement, a condition, and a post loop statement followed by a repeatable code block. Each must be separated with sub-statement separators (‘;;’) except for the repeated code block. Variables declared in an initialization statement are scoped to the loop. A post statement is executed after each completed repeatable code block has executed (assuming a break statement was not encountered executing an until loop’s repeatable code block).

This code is valid:

print final : ()(...) = {
    // ...
}

countAndSkipOdds final : (output : Integer)() = {
    total := 0
    until i := 0 ;; i == 100 ;; ++i {
        if i % 2 == 0 {
            ++total
            print("Counting", i)
        } else
            print("Not counting", i)
    }
    return total
}

Alternative forms using the until loop:

print final : ()(...) = {
    // ...
}

doStuff final : (output : Integer)() = {
    total := 0

    // OKAY: only a condition and repeatable code block are present
    {
        i := 0
        until i == 100 {
            if i % 2 == 0 {
                ++total
                print("Counting", i)
            } else
                print("Not counting", i)
        }
    }

    // OKAY: an initialization and condition statement are present with
    // a repeatable code block
    until i: ;; i == 100 {
        ++i
        ++total
    }

    // OKAY: An initialization and condition statement are present and
    // and empty post loop statement. The repeatable code block is present.
    until i: ;; i == 100 ;; {} {
        print(i)
        ++i
        ++total
    }

    // OKAY: An initialization and condition statement are present. A
    // repeatable code block is present. The `;` operator causes multiple
    // statements in the repeatable code block to be combined together and
    // treated as a single statement at the same scope.
    until i: ;; i == 100
        print(i);
        +++i;
        ++total

    // OKAY: The `;` operator causes multiple statements in the post loop
    // statement to be combined together and treated as a single statement at
    // the same scope.
    until i: ;; i == 100 ;; ++i; ++total
        print(i)

    return total
}

redo while

A redo while statement will repeat over a code block while a condition is true and it will always execute a repeatable code block at least once.

print final : ()(...) = {
    // ...
}

skipDivisibleBy3 final : ()(starting : Integer, ending : Integer) = {

    redo while starting < ending {
        if starting % 3 == 0
            print("Skip", starting)
        else
            print("Count", starting)

        ++starting
    }
}

redo while initialization statements and condition

A redo while statement will repeat over a code block while a condition is true and it will always execute a repeatable code block at least once. A redo while statement can contain an initialization statement with a condition followed by a repeatable code block which must be separated by a sub-statement separator (;;) except for the repeatable code block. If a value is declared in an initialization statement then that value’s scope only exists within the context of a redo while control flow.

print final : ()(...) = {
    // ...
}

skipDivisibleBy3 final : ()(ending : Integer) = {

    redo while starting := ending - 100 ;; starting < ending {
        if starting % 3 == 0
            print("Skip", starting)
        else
            print("Count", starting)

        ++starting        
    }
}

redo while initialization statements, condition, and post statements

A redo while statement will repeat over a code block while a condition is true and it will always execute a repeatable code block at least once. A redo while statement can contain an initialization statement with a condition and post loop statement followed by a repeatable code block which must be separated by a sub-statement separator (;;) except for the repeatable code block. If a value is declared in an initialization statement then that value’s scope only exists within the context of a redo while control flow.

An initialization statement and post loop statement are not mandatory but a repeatable code block must exist.

print final : ()(...) = {
    // ...
}

skipDivisibleBy3 final : ()(ending : Integer) = {
    redo while starting := ending - 100 ;; starting < ending ;; ++starting {
        if starting % 3 == 0
            print("Skip", starting)
        else
            print("Count", starting)
    }
}

An alternative form without pre-initialization:

print final : ()(...) = {
    // ...
}

skipDivisibleBy3 final : ()(starting: Integer, ending : Integer) = {
    redo while ;; starting < ending ;; ++starting {
        if starting % 3 == 0
            print("Skip", starting)
        else
            print("Count", starting)
    }
}

// OKAY: a single line where repeatable code is surrounded by a scope
// (the `false` will cause the loop to exit after the code block execution)
redo while false { print("hello") }

// OKAY: a single statement is allowed on the following line when a scope is
// not utilized for the repeatable code block
// (the `false` will cause the loop to exit after the code block execution)
redo while false
    print("hello")

redo until

A redo until statement will repeat over a code block until a condition is true and it will always execute a repeatable code block at least once.

print final : ()(...) = {
    // ...
}

assert final : ()(check : Boolean) = {
    // ...
}

skipDivisibleBy3 final : ()(starting : Integer, ending : Integer) = {
    assert(starting < ending)

    redo until starting == ending {
        if starting % 3 == 0
            print("Skip", starting)
        else
            print("Count", starting)

        ++starting
    }
}

redo until initialization statements and condition

A redo until statement will repeat over a code block until a condition is true and it will always execute a repeatable code block at least once. A redo until statement can contain an initialization statement with a condition followed by a repeatable code block which must be separated by a sub-statement separator (;;) except for the repeatable code block. If a value is declared in an initialization statement then that value’s scope only exists within the context of a redo until control flow.

print final : ()(...) = {
    // ...
}

assert final : ()(check : Boolean) = {
    // ...
}

skipDivisibleBy3 final : ()(ending : Integer) = {
    assert(starting < ending)

    redo until starting := ending - 100 ;; starting == ending {
        if starting % 3 == 0
            print("Skip", starting)
        else
            print("Count", starting)

        ++starting        
    }
}

redo until initialization statements, condition, and post statements

A redo until statement will repeat over a code block until a condition is true and it will always execute a repeatable code block at least once. A redo until statement can contain an initialization statement with a condition and post loop statement followed by a repeatable code block which must be separated by a sub-statement separator (;;) except for the repeatable code block. If a value is declared in an initialization statement then that value’s scope only exists within the context of the redo until control flow.

An initialization statement and a post loop statement are not mandatory but a repeatable code block must exist.

print final : ()(...) = {
    // ...
}

assert final : ()(check : Boolean) = {
    // ...
}

skipDivisibleBy3 final : ()(ending : Integer) = {
    assert(starting < ending)

    redo until starting := ending - 100 ;; starting < ending ;; ++starting {
        if starting % 3 == 0
            print("Skip", starting)
        else
            print("Count", starting)
    }
}

An alternative form without pre-initialization:

print final : ()(...) = {
    // ...
}

assert final : ()(check : Boolean) = {
    // ...
}

skipDivisibleBy3 final : ()(starting: Integer, ending : Integer) = {
    assert(starting < ending)

    redo until ;; starting < ending ;; ++starting {
        if starting % 3 == 0
            print("Skip", starting)
        else
            print("Count", starting)
    } 
}

// OKAY: a single line where the repeatable code block is surrounded by a scope
// (the `true` will cause the loop to exit following the code block execution)
redo until true { print("hello") }

// OKAY: a single statement is allowed on the following line as a scope
// is not present around the repeatable code block
// (the `true` will cause the loop to exit following the code block execution)
redo until true
    print("hello")

each

The each keyword and in keyword iterate through a type’s contents. For enumerators, the contents are the declared enumerator values. For types, the contents are each individual contained variable.

print final : ()(...) = {
    // ...
}

Fruit :: enum {
    Apple,
    Banana,
    Pear,
    Orange
}

listFruit final : ()() = {
    each fruit : in Fruit {
        print(fruit)
    }
}

These alternative versions will not compile:

listFruitAlt final : ()() = {
    // ERROR: missing `in` keyword and a `;;` is not appropriate since `each`
    // does not contain separated sub-statements in this form
    each fruit: ;; Fruit {
        print(fruit)
    }
}

listFruitAlt2 final : ()() = {
    // ERROR: missed capturing a value
    each Fruit {
        print(Fruit)
    }
}

Using each / in to iterate over a type’s values

The each keyword can be used to iterate over all variables contained in a type. A repeatable code block that follows an each keyword will be re-compiled per subtype to ensure that different subtypes remain compile-time strict.

print final : ()(...) = {
    // ...
}

MyType :: type {
    value1 : Integer
    value2 : String
}

myType : MyType

myType.value1 = 42
myType.value2 = "Life"

each value: in MyType
    print(value)            // will print `42` followed by "Life"

each / in initializer statement and condition

An each statement can contain an initialization statement with a condition followed by repeatable code block which must be separated by a sub-statement separator (;;) except for the repeatable code block. If a value is declared in an initialization statement then that value’s scope only exists within the context of the each control flow.

In the example below, the returned array is captured and iterated one element at a time:

print final : ()(...) = {
    // ...
}

MyType :: type {
    id : String
    value1 : Integer
    value2 : String
}

returnAMyType final : (myType : MyType)() = {
    myType.id = "ABC123"
    myType.value1 = 42
    myType.value2 = "Life"
    return myType
}

each myType := returnAMyType() ;; value : in myType {
    print(value, myType.id)             // will print `42` followed by "Life", and each time prints "ABC123"
}

Using each / in to iterate over a type’s value’s metadata

The each keyword can be used to iterate over all variables contained in a type and a variable’s metadata. A repeatable code block that follows an each keyword will be re-compiled per subtype to ensure that different subtypes remain compile-time strict.

print final : ()(...) = {
    // ...
}

MyType :: type {
    value1 : Integer
    value2 : String
}

myType : MyType

myType.value1 = 42
myType.value2 = "Life"

each value:, metadata: in MyType {
    print(value)            // will print `42` followed by "Life"
    print(metadata)         // will print information such as `value1` name
                            // and other variable properties
}

Using each / in to iterate an array

The each will use an array iteration to iterate through all entries in arrays.

print final : ()(...) = {
    // ...
}

values : String[3]
values[0] = "bird"
values[1] = "plane"
values[2] = "superman"

// the iterated type is treated as a range type and the values are iterated
// based on the range's evaluation
each value: in values
    print(value)    // will print values in order

Using each / from to iterate a range

The each will use range iterator to iterate through the entries in a range.

print final : ()(...) = {
    // ...
}

reverseView final : (result :)(values : Integer[3] &) = {
    // ... logic is covered in ranges ...    
}

values : String[3]
values[0] = "bird"
values[1] = "plane"
values[2] = "superman"

// the iterated type is treated as a range type and the values are iterated
// based on the range's evaluation
each value: in values
    print(value)    // will print values in order

// a range type is returned and the values are iterated based on the range's
// evaluation
each value : from reverseView(values)
    print(value)    // will print values in reversed order

each / from initializer statement and range iteration

A each statement can contain a initialization statement with a condition followed by a repeatable code block which must be separated by a sub-statement separator (;;) except for the repeatable code block. If a value is declared in an initialization statement then that value’s scope only exists within the context of the for control flow.

print final : ()(...) = {
    // ...
}

reverseView final : (result :)(values : Integer[3] &) = {
    // ... logic is covered in ranges ...    
}

returnAnArray final : (result : )() = {
    values : String[3]
    values[0] = "bird"
    values[1] = "plane"
    values[2] = "superman"
    return values
}

// an initialization statement is present; a range type is returned and the
// values are iterated based on the range's evaluation
each array := returnAnArray() ;; value : from reverseView(array)
    print(value, array[0])    // will print values in reversed order,
                              // and "bird" each time

switch

The switch, case and default flow control

A switch statement can be used to test a variable against a set of values. A switch statement will compare against a value list and execute zero or more statements based on values tested. A switch value is compared against each case value for equality and if default is present then any switch value that does not match an existing case causes a default code block to be executed.

doSomething final : ()() = {
    // ...
}

coinFlip final : (result : Boolean)() = {
    // ... return `true` or `false` randomly ...
}

func final : ()(value : Integer) = {
    switch value {
        case 1 {
            if coinFlip()
                break
            doSomething()

            // unlike other languages, a `break` is not required between
            // `case` statements as the code logic will not flow through from
            // one case to another automatically
        }
        case 2
            // single statement is executed then the `switch` exits
            doSomething()
        case 3
        case 4 {
            // if `value` is `3` or `4` two statements are executed and then
            // the `switch` exits
            doSomething()
            doSomething()
        }
        case 5
        case 6
            doSomething()
            // ERROR: this code will not compile as multiple statements are
            // present thus requiring using a `{}` scope or the `;` operator
            doSomething()
        case 7
        case 8
            // the `;` operator causes both statements to be joined as a
            // single statement at the same scope
            doSomething();
            doSomething()
        case 9
        case 10
        default {
            // values not `1` through `8` will execute this default scenario
            doSomething()
            doSomething()
        }
    }
}

Using switch to compare against runtime values

A switch statement can be used to compare against other runtime values. Values should not be computed inside a case statement but values can be used as a comparisons.

doSomething final : ()() = {
    // ...
}

coinFlip final : (result : Boolean)() = {
    // ... return `true` or `false` randomly ...
}

uniqueRandomNumber final : (result : Integer)() = {
    // .... return a random number never returned before ...
}

func final : ()(value : Integer) = {

    a := uniqueRandomNumber()
    b := uniqueRandomNumber()
    c := uniqueRandomNumber()
    d := uniqueRandomNumber()

    switch value {
        case a {
            if coinFlip()
                break
            doSomething()

            // a `break` is not required between `case` statements as the code
            // logic will not flow through from one case to another
            // automatically
        }
        case b
            // single statement is executed then the `switch` exits
            doSomething()
        case c
        case d {
            // if `value` is `c` or `d` two statements are executed and then
            // the `switch` exits
            doSomething()
            doSomething()
        }
    }
}

Using switch with complex types

A switch statement can be used to compare against complex types. Complex types must have comparison operator support.

The example below uses String types (but any type could be used):

doSomething final : ()() = {
    // ...
}

coinFlip final : (result : Boolean)() = {
    // ... return `true` or `false` randomly ...
}

uniqueFruit final : (result : String)() = {
    // .... return a unique random fruit name ...
}

func final : ()(fruit : String) = {

    a := uniqueFruit()
    b := uniqueFruit()
    c := uniqueFruit()

    realD := uniqueFruit()

    d : String * = realD

    switch fruit {
        case a {
            if coinFlip()
                break
            doSomething()
        }
        case b
            // single statement is executed then the `switch` exits
            doSomething()
        case c
        case d. {
            // if `fruit` is `c` or `d` two statements are executed and then
            // the `switch` exits
            doSomething()
            doSomething()
        }
    }
}

Using switch with alternative operators

A switch statement can be used with other binary operators that return a Boolean value. When binary operators are used, evaluation ordering of binary conditions occur in the same order as case conditions.

doSomething final : ()() = {
    // ...
}

coinFlip final : (result : Boolean)() = {
    // ... return `true` or `false` randomly ...
}

uniqueRandomNumber final : (result : Integer)() = {
    // .... return a random number never returned before ...
}

func final : ()(value : Integer) = {
    switch value {
        case < a {
            if coinFlip()
                break
            doSomething()

            // a `break` is not required between `case` statements as the code
            // logic will not flow through from one `case` to another
            // automatically
        }
        case b
            // single statement is executed then the `switch` exits
            doSomething()
        case > c
        case < d {
            // if `value` is `c` or `d` two statements are executed and then
            // the `switch` exits
            doSomething()
            doSomething()
        }
    }
}

switch statement and condition

A switch statement can contain a statement followed by a variable to test which must be separated by a sub statement separator (;;) operator. If a value is declared in an initialization statement then that value’s scope only exists within the context of a switch control flow. This scenario can be useful to capture a computed value, test the computed value, and later access the previously computed value.

doSomething final : ()() = {
    // ...
}

coinFlip final : (result : Boolean)() = {
    // ... return `true` or `false` randomly ...
}

uniqueRandomNumber final  : (result : Integer)() = {
    // .... return a random number never returned before ...
}

func final : ()(value : Integer) = {

    a := uniqueRandomNumber()
    b := uniqueRandomNumber()
    c := uniqueRandomNumber()
    d := uniqueRandomNumber()

    switch value := uniqueRandomNumber() ;; value {
        case a {
            // use captured value
            if value < 0 && coinFlip()
                break
            doSomething()

            // a `break` is not required between `case` statements as the code
            // logic will not flow through from one `case` to another
            // automatically
        }
        case b
            // single statement is executed then the `switch` exits
            doSomething()
        case c
        case d {
            // if `value` is `c` or `d` two statements are executed and then
            // the `switch` exits
            doSomething()
            doSomething()
        }
    }
}

switch statement and case continue

A case continue statement will cause the next case clause to be processed as if the following case (or default) condition were true. Effectively this allows for one case’s statement to fallthrough to another case’s statement.

doSomething final : ()(value : Integer) = {
    // ...
}

coinFlip final : (result : Boolean)() = {
    // ... return `true` or `false` randomly ...
}

func final : ()(value : Integer) = {
    switch value {
        case 1 {
            if coinFlip()        // `if coinFlip()` is `true`
                case continue    // will cause the next `case 2` to `continue`
                                 // processing as if it were a true thus causing
                                 // `doSomething(2)` to execute but not
                                 // `doSomething(1)`

            doSomething(1)

            // unlike other languages, a `break` is not required between
            // `case` statements as the code logic will not flow through from
            // one case to another automatically
        }
        case 2
            // single statement is executed then the `switch` exits
            doSomething(2)
        case 3
        case 4 {
            // if `value` is `3` or `4` two statements are executed and then
            // the `switch` exits
            doSomething(3)
            doSomething(4)
        }
        case 5
        case 6
            doSomething(5)
            // ERROR: this code will not compile as multiple statements are
            // present thus requiring using a `{}` scope or the `;` operator
            doSomething(6)
        case 7
        case 8
            // the `;` operator causes both statements to be joined as a
            // single statement at the same scope
            doSomething(7);
            doSomething(8)
        case 9
        case 10
        default {
            // values not `1` through `8` will execute this default scenario
            doSomething(9)
            doSomething(10)
        }
    }
}

using statement

A using statement is akin to a shortened if statement where a condition is not specified and always assumed to be true. This allows a temporary resource to declared and used within a using scope. Unlike a scope capture where variables outside the scope become restricted, a using allows full usage of local variables. If a value is declared in an initialization statement then that value’s scope only exists within the context of a using control flow.

print final : ()(...) = {
    // ...
}

MyType :: type {
    value1 : Integer
    value2 : String
}

func final : (myType : MyType)() = {
    // ...
    return myType
}

using value := func()
    doSomething(value)

using value := func() {
    print(value.value1)
    print(value.value2)
}

using value own := func() {
    print(value1)
    print(value2)
}

using value own := func()
    doSomething(value);
    print(value2)

forever

A forever statement will repeat over a code block until that code issues a break (or continue with a named scope). A forever statement is akin to a shorthand while where a condition is not specified and always assumed to be true. This can also be useful for logic that might have a mid-loop conditional exit.

print final : ()(...) = {
    // ...
}

countToOneHundred final : ()(starting : Integer) = {
    // repeat until starting is larger than 100
    forever {
        print(starting)
        if starting > 100
            break
        ++starting
    }
}

forever initialization statement

A forever statement can contain an initialization statement. If a value is declared in the initialization statement then that value’s scope only exists within the context of a while control flow.

print final : ()(...) = {
    // ...
}

fetchNumberFromCosmos final : (output : Integer)() = {
    // ... returns cosmic number
}

countToCosmicNumber final : ()(starting : Integer) = {
    forever endingNumber := fetchNumberFromCosmos() {
        print(starting)
        if (starting > endingNumber)
            break
        ++starting
    }
}

forever initialization statement and post loop statement

A forever loop can contain an initialization and a post loop statement prior to a repeatable code block. All must be separated with sub-statement separators (‘;;’) except for the repeatable code block. Variable declared in the initialization statement are scoped to the iterated loop. A post loop statement is executed after each completed forever’s repeatable code block has executed (assuming a break statement was not encountered executing the forever loop’s repeatable code block).

This code is valid:

print final : ()(...) = {
    // ...
}

countAndSkipOdds final : (output : Integer)() = {
    total := 0
    forever i := 0 ;; ++i {
        if i % 2 == 0 {
            ++total
            print("Counting", i)
            if i > 100
                break
        } else
            print("Not counting", i)
    }
    return total
}

Alternative forms using a forever loop:

print final : ()(...) = {
    // ...
}

doStuff final : (output : Integer)() = {
    total := 0

    // no initialization or post-loop statement before the repeatable code block
    {
        i := 0
        forever {
            if i % 2 == 0 {
                ++total
                print("Counting", i)
                if i > 100
                    break
            } else
                print("Not counting", i)
        }
    }

    // an initialization statement is present prior to the repeatable code block
    forever i: {
        ++i
        if i > 100
            break
        ++total
    }

    // an initialization statement and an empty post loop statement is present
    // followed by a repeatable code block
    forever i: ;; {} {
        ++i
        if i > 100
            break
        ++total
    }

    // an initialization statement and post loop statement is present followed
    // by a repeatable code block (although it will repeat forever)
    forever i: ;; ++i
        print(i)

    // The `;` operator is used to combine a post loop statement as if it were
    // a single statement.
    forever i: ;; ++i; ++total
        print(i)

    // The `;` operator is used to combine a repeatable code block as if it
    // were a single statement.
    forever i: ;; ++i
        print(i);
        print(i % 2)

    return total
}

Value polymorphism using if

An if statement can also be used in a function declaration to indicate that a function supports value polymorphism. Which function to call is based on a pre-condition check for a given if statement. The compiler will execute each test based on the order of appearance in code if no specific order has a bias. If no match is found (and if present) then a undecorated version of a function will be executed. A compiler may decide to reorder tests if the reordering will have no net resulting impact on the code flow. Care should be taken to not have overlapping pre-conditions if code order cannot be preserved or guaranteed. The [[likely]] and [[unlikely]] compiler directives can be used as a hint to a compiler which execution path is more likely to be followed (thus tests can be reordered appropriately).

If some value polymorphic functions are declared using an if statement then a single polymorphic version function using the same types can be declared as a catch-all if none of the other conditions succeed (i.e. the logical equivalent of a switch default statement). If no function was found a panic may be issued.

Only functions marked as final support value polymorphism. A conditional check on a function cannot be replaced and any assignment of a changeable functions would be ambiguous to which value polymorphic version should be replaced. However, a function without any value polymorphism if condition can be varies allowing the function to be reassigned to a new function implementation that will assume to replace only a default non-conditional version (i.e. a version that does not contain value polymorphism).

random final : (value : Integer)() = {
    // ... return a positive or negative integer
}

func final : ()(value : Integer) if { return value > 0 } = {
    // ...
}

func final : ()(value : Integer) = {
    // ...
}

forever {
    // each time the function is called a different function may be invoked
    func(random())
}

Another example computing factorial:

assert final : ()() = {
    // ...
}

factorial final : (r : Integer)(n : Integer) if { return n > 1 } = {
    return n * factorial(n - 1)
}

factorial final : (r : Integer)(n : Integer) = {
    return 1
}

assert(120 == factorial(5))

An example of a children’s game of FizzBuzz using value polymorphism:

print final : ()(...) = {
    // ...
}

toString final : (result : String)(value : Integer) = {
    // ...
}

next final : (s: String)(i : Integer) if [[unlikely]] { return i % 15 == 0 } = {
    return "FizzBuzz"
}

next final : (s: String)(i : Integer) if [[likely]] { return i % 3 == 0 } = {
    return "FizzBuzz"
}

next final : (s: String)(i : Integer) if { return i % 5 == 0 } = {
    return "Buzz"
}

// next is not marked as `final` and can be replaced with an alternative
// implementation
next : (s: String)(i : Integer) [[likely]] = {
    return toString(i)
}

// displays: 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, ... 14, FizzBuz, ...
while i := 1 ;; i < 100 ;; ++i {
    print(next())
}

Value polymorphism using if on nothing instances

A nothing instance can filter between normal function calls and functions that are called on a nothing instance. By checking if a self pointer (_) is valid inside an if condition of a value polymorphic function, code can decide if a nothing version of a function or a normal version function should be called.

MyType :: type {
    +++ final : ()(:Nothing) = {
        // instance to a nothing type
    }

    doSomething final : ()( : Integer) if [[unlikely]] { return !_ } = {
        // do nothing -- inside nothing instance of MyType
    }
    doSomething final : ()(value : Integer) = {
        // ...
        // do something -- normal instance of MyType
        // ...
    }
}

myType1 : MyType *      // points to nothing
MyType2 : MyType * @    // points to an allocated instance

myType1.doSomething()   // does nothing
myType2.doSomething()   // does something