Learn SugarIntermediate

Match expressions

Use match to compare values against literals, alternatives, ranges, and fixed-list structures.

match compares one value against an ordered set of patterns. It is useful when an if chain would repeat the same comparison many times.

text {
  let number = 13;

  match number {
    1 => "One!",
    2 | 3 | 5 | 7 | 11 | 13 => "This is a prime",
    13..=19 => "A teen",
    _ => "Not special",
  }
}

Sugar checks the arms from top to bottom. The first matching arm wins, so 13 produces "This is a prime" before Sugar reaches the teen range.

Return a value

match is an expression. Its selected arm becomes its value:

let binary = match damaged {
  false => 0,
  true => 1,
};

The same value form can initialize a variable or constant:

const growthStage = match growth {
  0..=99 => 1,
  100..=199 => 2,
  200..=299 => 3,
  _ => 4,
};

A match can also appear inside a larger expression. Its arms remain lazy, so Sugar evaluates only the selected result:

const reward = if score < 0 then 0 else match rank {
  "BRONZE" => 10,
  "SILVER" => 20,
  "GOLD" => 40,
  _ => 0,
};

It can also be the final expression of a program:

match mood {
  "HAPPY" => "@1 is glowing today!",
  "TIRED" => "@1 needs a quiet moment.",
  _ => "@1 is taking the day as it comes.",
}

The value after match is evaluated once. A subject such as Rand::pick(1..=100) rolls once and compares that one result with every arm.

Combine patterns

Use | when several patterns should share one result:

match roll {
  1 | 2 | 3 => "Low roll",
  4 | 5 => "Good roll",
  6 => "Perfect roll!",
  _ => "Unexpected roll",
}

Match number ranges

Number patterns use the same range rules as the rest of Sugar:

match score {
  0..50 => "Below 50",
  50..=89 => "Passing",
  90..=100 => "Excellent",
  _ => "Outside the expected score",
}

0..50 includes 0 through 49. 50..=89 includes both 50 and 89.

Match several values together

Put values in a list when one decision depends on their combination. Then use a fixed-list pattern with the same shape:

match ($species, $personality) {
  ("SULCATA", "CURIOUS") => "CURIOUS",
  ("SULCATA", "DETERMINED") => "RESTLESS",
  ("SULCATA", _) => "RELAXED",
  ("WOLF", "PLAYFUL") => "PLAYFUL",
  ("WOLF", _) => "CALM",
  _ => "NONE",
}

("SULCATA", _) means a two-entry list whose first value is "SULCATA"; _ accepts any second value. It does not match a one-entry or three-entry list because fixed-list patterns require the exact same length.

Each position can use the patterns you already know, including alternatives and ranges:

match ($species, $age) {
  ("SULCATA" | "WOLF", 0..=2) => "YOUNG",
  (_, 3..=10) => "GROWN",
  _ => "OTHER",
}

Patterns may also be nested when the subject contains nested lists. Structural matching checks values; it does not create variables or unpack the list. As with every match, Sugar checks arms from top to bottom and uses the first match.

Run several instructions

Put braces after => when an arm needs a full program. This complete Boop Code module declares the shared values and performs one roll:

var health = 100;
var xp = 0;

text {
  let roll = Rand::pick(1..=100);

  match roll {
    1 => {
      health -= 10;
      "Critical failure!"
    },

    100 => {
      xp += 20;
      "Perfect roll!"
    },

    _ => format("You rolled {roll}"),
  }
}

Only the selected arm runs. Its final expression supplies the value of the match.

Cover every possible value

_ matches anything not handled earlier and must be the last arm. Sugar normally requires it so the match always produces a value.

A boolean match is already complete when it contains both true and false:

match enabled {
  true => "Enabled",
  false => "Disabled",
}

Match patterns can be numbers, strings, booleans, None, number ranges, fixed lists containing other patterns, alternatives joined with |, or _.

The next lesson introduces complete Item action declarations. Memory variables follow once there is an action that can change them.