Slide 27 of 74

Matching with is

Variants, and what they bind
type Shape {
	Circle    { radius: Int }
	Rectangle { width: Int, height: Int }
	Point
}

func describe(shape: Shape): Str {
	if shape is Shape.Circle(r) && r > 10 {
		return "a big circle"
	} else if shape is Shape.Circle(r) {
		return "a circle of {r}"
	} else if shape is Shape.Rectangle(w, _) {
		return "a rectangle {w} wide"
	}
	return "a point"
}

proc main(): void {
	echo describe(Shape.Circle(40))
	echo describe(Shape.Circle(4))
	echo describe(Shape.Rectangle(3, 9))
	echo describe(Shape.Point())
}
A name in a pattern is always new
proc main(): void {
	wanted := 3
	found := indexOf([5, 3, 1], 3)

	// This `wanted` is a new name bound to whatever position came back:
	// it hides the outer one and compares with nothing.
	if found is Result.Ok(wanted) {
		echo "at {wanted}"
	}
	// To test for a particular value, write it in its place...
	if found is Result.Ok(1) {
		echo "second, as expected"
	}
	// ...or bind it and compare.
	if found is Result.Ok(at) && at > 0 {
		echo "not first"
	}
	echo wanted            // 3 — the outer one, untouched
}

value is Pattern is a Bool that is true when the value has that shape, and binds names for what it carries. There is no match statement: a match is an if, or an if/else if chain testing one subject.

  • A variant pattern names the variant and binds its fields by position, a variant's own fields first and the shared ones after: shape is Shape.Rectangle(w, h). It binds every field or none — Shape.Rectangle alone matches any rectangle — and _ takes a field without binding it.
  • Result.Ok(v) and Result.Error(e) are variant patterns too.
  • A name in a pattern is always a new name: it never compares with a variable already in scope. To test for a particular value, write the value itself in its place — Result.Ok(1) — or bind it and compare after &&.

A name a match binds is immutable. It is in scope in the branch the match guards and in the rest of the same condition after && — if r is Result.Ok(n) && n > 10 — but not in an else, and not past an ||, where nothing says which side matched.