plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


09d918f — Peter John 2026-10-25T17:27:30+05:30
docs(examples): multi-branch match error handling in error_propagation
plum-examples/error_propagation.plum CHANGED
@@ -6,8 +6,8 @@ import std/List
6
6
 
7
7
  # `Try[T, E]` is either `Ok(T)` or `Err(E)`. `E` is normally a tag union such
8
8
  # as `[NegativeNum, BadNumStr]`: a set of bare tags (optionally carrying a
9
- # payload, e.g. `InvalidJson(Str)`) that needs no declaration. There is no
9
+ # payload, e.g. `InvalidJson(Str)`) that needs no declaration. There is no `Option`:
10
- # A missing value is just an error tag like `[OutOfBounds]`.
10
+ # a missing value is just an error tag like `[OutOfBounds]`.
11
11
  #
12
12
  # `expr?` unwraps an `Ok`, or exits the enclosing function early with the
13
13
  # `Err` value. The error unions of different calls merge automatically into
@@ -62,6 +62,37 @@ fun mustBePositive(n: Int) -> Int =
62
62
  crash "n must not be negative"
63
63
  n
64
64
 
65
+ # Handling errors with `match`: one arm per tag, payloads bind like any
66
+ # variant field, and a match without `_` must cover every tag in the union.
67
+ fun parseAge(s: Str) -> Try[Int, [BadNumStr, Negative, TooOld(Int)]] =
68
+ n := parseInt(s)?
69
+ if n < 0
70
+ return Err(Negative)
71
+ if n > 150
72
+ return Err(TooOld(n))
73
+ return Ok(n)
74
+
75
+ fun describeAge(s: Str) -> Str =
76
+ match parseAge(s)
77
+ Ok(n) => "age {n}"
78
+ Err(BadNumStr) => "not a number"
79
+ Err(Negative) => "can't be negative"
80
+ Err(TooOld(n)) => "{n} is too old"
81
+
82
+ # A bare tag union can be matched directly too.
83
+ fun isRetryable(e: [Timeout, Refused, BadRequest(Str)]) -> Bool =
84
+ match e
85
+ Timeout => True
86
+ Refused => True
87
+ BadRequest(_) => False
88
+
89
+ # `_` catches whatever the earlier arms didn't.
90
+ fun ageOrDefault(s: Str) -> Int =
91
+ match parseAge(s)
92
+ Ok(n) => n
93
+ Err(TooOld(_)) => 150
94
+ _ => 0
95
+
65
96
  test "try operator unwraps Ok and propagates the value through two calls"
66
97
  r := sumTwo("2", "3")
67
98
  assert r.isOk()
@@ -117,3 +148,19 @@ test "default operator falls back to the given default on an empty list"
117
148
 
118
149
  test "crash is not reached on the happy path"
119
150
  assert mustBePositive(3) == 3
151
+
152
+ test "match handles each error tag in its own arm"
153
+ assert describeAge("42") == "age 42"
154
+ assert describeAge("abc") == "not a number"
155
+ assert describeAge("-3") == "can't be negative"
156
+ assert describeAge("200") == "200 is too old"
157
+
158
+ test "match on a bare tag union"
159
+ assert isRetryable(Timeout)
160
+ assert isRetryable(Refused)
161
+ assert !isRetryable(BadRequest("missing id"))
162
+
163
+ test "match falls back to a wildcard arm"
164
+ assert ageOrDefault("30") == 30
165
+ assert ageOrDefault("999") == 150
166
+ assert ageOrDefault("x") == 0