Pattern Matching

The when keyword replaces the transitional switch statement and ternary operator found in many other languages. It provides a more powerful and expressive way to handle conditional logic and pattern matching in Conjure.

Usage as statement

When using when as a statement, you can match against specific values or conditions and execute corresponding statements which must be enclosed in braces {}. Each case is separated by a newline.

In the event that none of the cases match, an optional else case can be provided to handle all other scenarios.

When a “tag” is provided (expression after the when keyword), the cases are used to perform an equality comparison against that value. Multiple values can be matched in a single case by separating them with commas.

when dayOfWeek {
	// Single statement without braces
	0, 6 { c.printf("It's the weekend\n") }

	// Multiple statements require braces
	1 {
		c.printf("It's Monday\n")
		c.printf("Start of the work week\n")
	}

	// Alternate case is handled using `else`
	else { c.printf("It's another day of the week.\n") }
}

If no tag is provided, each case is treated the same as an if condition, allowing for more complex expressions.

when {
	hour < 18 { c.printf("Good afternoon!\n") }
	hour < 12 { c.printf("Good morning!\n") }
	else { c.printf("Good evening!\n") }
}

Unlike switch statements in C, when statements do not fall through to subsequent cases. Once a matching case is found, its associated statements are executed, and the when statement is exited. You can use the fallthrough keyword to explicitly allow fallthrough behavior.

when score {
	2 {
		c.printf("Greater than zero\n")
		fallthrough  // Explicitly fall through to the next case
	}
	1 {
		c.printf("At least one\n")
		fallthrough  // Explicitly fall through to the next case
	}
	else: c.printf("Zero or negative\n")
}

To exit a when statement early, you can use the break keyword.

when command {
	"start" {
		c.printf("Starting...\n")
		break  // Exit the when statement
		c.printf("This line will never be reached\n")  // unreachable
	}
	else: c.printf("Unknown command\n")
}

When working with union and enum types, when statements must be exhaustively checked; meaning all possible variants have to be handled. This provides compile-time safety by ensuring that all cases are considered.

enum Color {
	Red
	Green
	Blue
}

var color = Color.Red

when color {
	Color.Red: c.printf("Color is Red\n")
	Color.Green: c.printf("Color is Green\n")
	// The lack of `else` or a case for Color.Blue
	// will result in a compile-time error
}

Usage in Expressions

Alongside its use as a control flow statement, when can also be used as an expression to produce values based on conditions. This is similar to the ternary operator (? :) found in other languages but with more flexibility and readability.

When using when as an expression, it evaluates to the value of the matching case. Each case must produce a value of the same type, and if no cases match, an optional else case can provide a default value.

Each case must use the : syntax to separate the condition from the resulting value. The value must also be an assignable expression.

var colorName = when color {
	Color.Red: "Red"
	Color.Green: "Green"
	Color.Blue: "Blue"
	else: "Unknown Color"
}