Match
Branch on a string union with match. Add a value to the union and shot check points at every match that doesn't handle it yet.
match takes a value whose type is a union of strings and runs the case for that value. It compiles to plain if / elseif Luau, line for line, and a value no case covers is an error when you check and when the game runs.
The shape
match reason
"Pickup" then return "Picked up " .. amount
"Shop" then return "Spent " .. amount
"Gift", "Prize" then
return "Got " .. amount
endmatchtakes a value whose type is a union of strings, likepublic type Reason = "Pickup" | "Shop" | "Gift" | "Prize"(Types).- Each case starts its line with one or more of the union's values, separated by commas, then
then. Its code follows on the same line or on the lines below, up to the next case. - An
else, if there is one, goes last and takes every value that has no case. endcloses it, like any block.
What shot check does with it
A value of the union with no case, when there is no else, is an error at the match:
Wallet/Toast.shot:5:3 match on Reason has no case for "Prize" (added at Wallet/Types.shot:2): add the case, or an elseSo adding a value to a union turns every match that must handle it into an error: your to-do list. shot matches Reason lists every match on Reason with the values each one leaves out (or covers with else).
- A case that is not a value of the union is an error:
match case "Shpo" is not one of the values it matches on: "Gift" | "Pickup" | "Shop"- A match on a plain string, not a union, has no list of values to check, so it needs an
else:
match on a string that is not a union of string values: shot can't tell whether its cases cover
everything, so give it an else- At run time, a value that no case covers (only possible when the data is wrong, like a typo in a saved file) raises "match: no case for <value>" instead of running the wrong branch.
Prefer a match without else: a new value then shows up everywhere it needs handling. Use else when the other values really all mean the same thing.
What it compiles to
do local __shotmatch1 : typeof(reason) = reason
if __shotmatch1 == "Pickup" then return "Picked up " .. amount
elseif __shotmatch1 == "Shop" then return "Spent " .. amount
elseif __shotmatch1 == "Gift" or __shotmatch1 == "Prize" then
return "Got " .. amount
else local __shotmatch_5 : nil = __shotmatch1 error("match: no case for " .. tostring(__shotmatch1)) end endThe output keeps the source line for line, so errors and stack traces keep their .shot lines, and the value is read once. The last line is how the check works: in that else, Luau's type checker knows which values are left, and the nil asks it to name them.
Limits
- Values are strings. For numbers, enums and other types write
if/elseif. matchis a keyword only at the start of a line and followed by a value, solocal match = ...,string.matchand a function calledmatchstill work.
