Conditionals

Programs need to make decisions. GX gives you two tools: if for simple branching and match for multi-way selection.

If / Elif / Else

The basics — check a condition, run the matching block:

fn main() {
    var score = 85

    if (score >= 90) {
        print("Grade: A\n")
    } elif (score >= 80) {
        print("Grade: B\n")
    } elif (score >= 70) {
        print("Grade: C\n")
    } elif (score >= 60) {
        print("Grade: D\n")
    } else {
        print("Grade: F\n")
    }
}

Conditions require parentheses. Braces are always required (no single-line if without braces).

Simple If

You don’t always need else:

fn main() {
    var health = 15

    if (health < 20) {
        print("Warning: Low health!\n")
    }

    if (health <= 0) {
        print("Game Over\n")
    }
}

Nested Conditions

Conditions can nest, but keep it readable:

fn main() {
    var age = 25
    var has_license = true

    if (age >= 18) {
        if (has_license) {
            print("You can drive\n")
        } else {
            print("Get a license first\n")
        }
    } else {
        print("Too young to drive\n")
    }
}

Often, && is cleaner than nesting:

fn main() {
    var age = 25
    var has_license = true

    if (age >= 18 && has_license) {
        print("You can drive\n")
    }
}

The Match Statement

When you’re comparing one value against many possibilities, match is cleaner than a chain of if/elif:

fn main() {
    var day = 3

    match (day) {
        1: print("Monday\n")
        2: print("Tuesday\n")
        3: print("Wednesday\n")
        4: print("Thursday\n")
        5: print("Friday\n")
        default: print("Weekend\n")
    }
}

Multiple Values

Comma-separate values that share the same action:

fn main() {
    var day = 6

    match (day) {
        1, 2, 3, 4, 5: print("Weekday\n")
        6, 7: print("Weekend!\n")
        default: print("Invalid day\n")
    }
}

Range Patterns

Match a range of values with .. (inclusive on both ends):

fn main() {
    var score = 85

    match (score) {
        0..59:   print("F\n")
        60..69:  print("D\n")
        70..79:  print("C\n")
        80..89:  print("B\n")
        90..100: print("A\n")
        default: print("Invalid score\n")
    }
}

Block Bodies

Use braces for multi-line match arms:

fn main() {
    var choice = 2

    match (choice) {
        1: {
            print("Option 1 selected\n")
            print("Loading...\n")
        }
        2: {
            print("Option 2 selected\n")
            print("Processing...\n")
        }
        default: print("Unknown option\n")
    }
}

Matching Enums

Match works beautifully with enums (you’ll learn more about enums in a later tutorial):

enum Direction { North South East West }

fn main() {
    var dir:Direction = East

    match (dir) {
        North: print("Going up\n")
        South: print("Going down\n")
        East:  print("Going right\n")
        West:  print("Going left\n")
    }
}

Try it — Write a match statement with ranges in the Playground.


Expert Corner

How match compiles: The GX compiler analyzes your match arms and generates either a C switch statement (for simple integer values) or a chain of if/else if (for ranges and complex patterns). The compiler picks the most efficient strategy automatically.

Why : instead of =>: GX uses colon in match arms (1: print("one")) for consistency. The colon already appears in for-range (1:5) and type annotations (var x:i32). Using => would add another symbol for no practical benefit. Less syntax to learn, fewer symbols to type.

Range patterns are inclusive on both ends: 0..59 matches 0, 1, 2, … 59. This matches the convention used by for-range loops (for (i = 0:59)) — consistency across the language reduces surprises.

default is not required when matching enums where you cover all variants. But it’s good practice for integer matches where you can’t cover every value.