Skip to content

Commit 9f59348

Browse files
authored
Document built-in exceptions (#880)
* Document built-in exceptions * requested changes * add link to result api * fix typos
1 parent fd3cd56 commit 9f59348

File tree

1 file changed

+257
-23
lines changed

1 file changed

+257
-23
lines changed

pages/docs/manual/latest/exception.mdx

+257-23
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,36 @@ canonical: "/docs/manual/latest/exception"
66

77
# Exception
88

9-
Exceptions are just a special kind of variant, thrown in **exceptional** cases (don't abuse them!).
9+
Exceptions are just a special kind of variant, thrown in **exceptional** cases (don't abuse them!). Consider using the [`option`](null-undefined-option.mdx) or [`result`](api/core/result) type for recoverable errors.
1010

11-
## Usage
11+
You can create your own exceptions like you'd make a variant (exceptions need to be capitalized too).
12+
13+
<CodeTab labels={["ReScript", "JS Output"]}>
14+
15+
```res example
16+
exception InputClosed(string)
17+
// later on
18+
raise(InputClosed("The stream has closed!"))
19+
```
20+
```js
21+
import * as Caml_exceptions from "./stdlib/caml_exceptions.js";
22+
23+
var InputClosed = /* @__PURE__ */Caml_exceptions.create("Playground.InputClosed");
24+
25+
throw {
26+
RE_EXN_ID: InputClosed,
27+
_1: "The stream has closed!",
28+
Error: new Error()
29+
};
30+
```
31+
32+
</CodeTab>
33+
34+
## Built-in Exceptions
35+
36+
ReScript has some built-in exceptions:
37+
38+
### `Not_found`
1239

1340
<CodeTab labels={["ReScript", "JS Output"]}>
1441

@@ -29,16 +56,16 @@ let result =
2956
}
3057
```
3158
```js
32-
var Caml_js_exceptions = require("./stdlib/caml_js_exceptions.js");
59+
import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
3360

3461
function getItem(item) {
3562
if (item === 3) {
3663
return 1;
3764
}
3865
throw {
39-
RE_EXN_ID: "Not_found",
40-
Error: new Error()
41-
};
66+
RE_EXN_ID: "Not_found",
67+
Error: new Error()
68+
};
4269
}
4370

4471
var result;
@@ -71,17 +98,15 @@ switch list{1, 2, 3}->List.getExn(4) {
7198
}
7299
```
73100
```js
74-
var List = require("./stdlib/list.js");
75-
var Caml_js_exceptions = require("./stdlib/caml_js_exceptions.js");
101+
import * as Core__List from "./stdlib/core__List.js";
102+
import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
76103

77104
var exit = 0;
78105

79106
var item;
80107

81108
try {
82-
item = List.find((function (i) {
83-
return i === 4;
84-
}), {
109+
item = Core__List.getExn({
85110
hd: 1,
86111
tl: {
87112
hd: 2,
@@ -90,7 +115,7 @@ try {
90115
tl: /* [] */0
91116
}
92117
}
93-
});
118+
}, 4);
94119
exit = 1;
95120
}
96121
catch (raw_exn){
@@ -109,25 +134,234 @@ if (exit === 1) {
109134

110135
</CodeTab>
111136

112-
You can also make your own exceptions like you'd make a variant (exceptions need to be capitalized too).
137+
### `Invalid_argument`
138+
139+
Used to check if argument is valid. This exception takes a string.
140+
141+
<CodeTab labels={["ReScript", "JS Output"]}>
142+
```res example
143+
let divide = (a, b) =>
144+
if b == 0 {
145+
raise(Invalid_argument("Denominator is zero"))
146+
} else {
147+
a / b
148+
}
149+
150+
// catch error
151+
try divide(2, 0)->Console.log catch {
152+
| Invalid_argument(msg) => Console.log(msg) // Denominator is zero
153+
}
154+
```
155+
156+
```js
157+
import * as Caml_int32 from "./stdlib/caml_int32.js";
158+
import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
159+
160+
function divide(a, b) {
161+
if (b === 0) {
162+
throw {
163+
RE_EXN_ID: "Invalid_argument",
164+
_1: "Denominator is zero",
165+
Error: new Error()
166+
};
167+
}
168+
return Caml_int32.div(a, b);
169+
}
170+
171+
try {
172+
console.log(divide(2, 0));
173+
}
174+
catch (raw_msg){
175+
var msg = Caml_js_exceptions.internalToOCamlException(raw_msg);
176+
if (msg.RE_EXN_ID === "Invalid_argument") {
177+
console.log(msg._1);
178+
} else {
179+
throw msg;
180+
}
181+
}
182+
```
183+
184+
</CodeTab>
185+
186+
### `Assert_failure`
187+
188+
Raise when you use `assert(condition)` and `condition` is false. The arguments
189+
are the location of the `assert` in the source code (file name, line number, column number).
113190

114191
<CodeTab labels={["ReScript", "JS Output"]}>
115192

116193
```res example
117-
exception InputClosed(string)
118-
// later on
119-
raise(InputClosed("The stream has closed!"))
194+
let decodeUser = (json: JSON.t) =>
195+
switch json {
196+
| Object(userDict) =>
197+
switch (userDict->Dict.get("name"), userDict->Dict.get("age")) {
198+
| (Some(String(name)), Some(Number(age))) => (name, age->Float.toInt)
199+
| _ => assert(false)
200+
}
201+
| _ => assert(false)
202+
}
203+
204+
205+
try decodeUser(%raw("{}"))->Console.log catch {
206+
| Assert_failure(loc) => Console.log(loc) // ("filename", line, col)
207+
}
120208
```
209+
121210
```js
122-
var Caml_exceptions = require("./stdlib/caml_exceptions.js");
211+
mport * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
212+
213+
function decodeUser(json) {
214+
if (!Array.isArray(json) && (json === null || typeof json !== "object") && typeof json !== "number" && typeof json !== "string" && typeof json !== "boolean") {
215+
throw {
216+
RE_EXN_ID: "Assert_failure",
217+
_1: [
218+
"playground.res",
219+
8,
220+
9
221+
],
222+
Error: new Error()
223+
};
224+
}
225+
if (typeof json === "object" && !Array.isArray(json)) {
226+
var match = json["name"];
227+
var match$1 = json["age"];
228+
if (match !== undefined && !(!Array.isArray(match) && (match === null || typeof match !== "object") && typeof match !== "number" && typeof match !== "string" && typeof match !== "boolean") && typeof match === "string" && match$1 !== undefined && !(!Array.isArray(match$1) && (match$1 === null || typeof match$1 !== "object") && typeof match$1 !== "number" && typeof match$1 !== "string" && typeof match$1 !== "boolean") && typeof match$1 === "number") {
229+
return [
230+
match,
231+
match$1 | 0
232+
];
233+
}
234+
throw {
235+
RE_EXN_ID: "Assert_failure",
236+
_1: [
237+
"playground.res",
238+
6,
239+
11
240+
],
241+
Error: new Error()
242+
};
243+
}
244+
throw {
245+
RE_EXN_ID: "Assert_failure",
246+
_1: [
247+
"playground.res",
248+
8,
249+
9
250+
],
251+
Error: new Error()
252+
};
253+
}
254+
255+
try {
256+
console.log(decodeUser({}));
257+
}
258+
catch (raw_loc){
259+
var loc = Caml_js_exceptions.internalToOCamlException(raw_loc);
260+
if (loc.RE_EXN_ID === "Assert_failure") {
261+
console.log(loc._1);
262+
} else {
263+
throw loc;
264+
}
265+
}
266+
```
267+
268+
</CodeTab>
123269

124-
var InputClosed = Caml_exceptions.create("MyFile.InputClosed");
270+
### `Failure`
125271

126-
throw {
127-
RE_EXN_ID: InputClosed,
128-
_1: "The stream has closed!",
129-
Error: new Error()
130-
};
272+
Exception raised to signal that the given arguments do not make sense. This
273+
exception takes a string as an argument.
274+
275+
276+
<CodeTab labels={["ReScript", "JS Output"]}>
277+
```res example
278+
let isValidEmail = email => {
279+
let hasAtSign = String.includes(email, "@")
280+
let hasDot = String.includes(email, ".")
281+
if !(hasAtSign && hasDot) {
282+
raise(Failure("Invalid email address"))
283+
} else {
284+
true
285+
}
286+
}
287+
288+
289+
let isValid = try isValidEmail("rescript.org") catch {
290+
| Failure(msg) => {
291+
Console.error(msg)
292+
false
293+
}
294+
}
295+
```
296+
297+
```js
298+
import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
299+
300+
function isValidEmail(email) {
301+
var hasAtSign = email.includes("@");
302+
var hasDot = email.includes(".");
303+
if (hasAtSign && hasDot) {
304+
return true;
305+
}
306+
throw {
307+
RE_EXN_ID: "Failure",
308+
_1: "Invalid email address",
309+
Error: new Error()
310+
};
311+
}
312+
313+
var isValid;
314+
315+
try {
316+
isValid = isValidEmail("rescript.org");
317+
}
318+
catch (raw_msg){
319+
var msg = Caml_js_exceptions.internalToOCamlException(raw_msg);
320+
if (msg.RE_EXN_ID === "Failure") {
321+
console.error(msg._1);
322+
isValid = false;
323+
} else {
324+
throw msg;
325+
}
326+
}
327+
```
328+
329+
</CodeTab>
330+
331+
### `Division_by_zero`
332+
333+
Exception raised by integer division and remainder operations when their second argument is zero.
334+
335+
336+
<CodeTab labels={["ReScript", "JS Output"]}>
337+
```res example
338+
// ReScript raise `Division_by_zero` if the denominator is zero
339+
let result = try Some(10 / 0) catch {
340+
| Division_by_zero => None
341+
}
342+
343+
Console.log(result) // None
344+
```
345+
346+
```js
347+
import * as Caml_int32 from "./stdlib/caml_int32.js";
348+
import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
349+
350+
var result;
351+
352+
try {
353+
result = Caml_int32.div(10, 0);
354+
}
355+
catch (raw_exn){
356+
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
357+
if (exn.RE_EXN_ID === "Division_by_zero") {
358+
result = undefined;
359+
} else {
360+
throw exn;
361+
}
362+
}
363+
364+
console.log(result);
131365
```
132366

133367
</CodeTab>

0 commit comments

Comments
 (0)