diff --git a/pages/docs/manual/latest/exception.mdx b/pages/docs/manual/latest/exception.mdx index d3e2cea9b..f68c2d1d7 100644 --- a/pages/docs/manual/latest/exception.mdx +++ b/pages/docs/manual/latest/exception.mdx @@ -6,9 +6,36 @@ canonical: "/docs/manual/latest/exception" # Exception -Exceptions are just a special kind of variant, thrown in **exceptional** cases (don't abuse them!). +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. -## Usage +You can create your own exceptions like you'd make a variant (exceptions need to be capitalized too). + + + +```res example +exception InputClosed(string) +// later on +raise(InputClosed("The stream has closed!")) +``` +```js +import * as Caml_exceptions from "./stdlib/caml_exceptions.js"; + +var InputClosed = /* @__PURE__ */Caml_exceptions.create("Playground.InputClosed"); + +throw { + RE_EXN_ID: InputClosed, + _1: "The stream has closed!", + Error: new Error() + }; +``` + + + +## Built-in Exceptions + +ReScript has some built-in exceptions: + +### `Not_found` @@ -29,16 +56,16 @@ let result = } ``` ```js -var Caml_js_exceptions = require("./stdlib/caml_js_exceptions.js"); +import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js"; function getItem(item) { if (item === 3) { return 1; } throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; + RE_EXN_ID: "Not_found", + Error: new Error() + }; } var result; @@ -71,17 +98,15 @@ switch list{1, 2, 3}->List.getExn(4) { } ``` ```js -var List = require("./stdlib/list.js"); -var Caml_js_exceptions = require("./stdlib/caml_js_exceptions.js"); +import * as Core__List from "./stdlib/core__List.js"; +import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js"; var exit = 0; var item; try { - item = List.find((function (i) { - return i === 4; - }), { + item = Core__List.getExn({ hd: 1, tl: { hd: 2, @@ -90,7 +115,7 @@ try { tl: /* [] */0 } } - }); + }, 4); exit = 1; } catch (raw_exn){ @@ -109,25 +134,234 @@ if (exit === 1) { -You can also make your own exceptions like you'd make a variant (exceptions need to be capitalized too). +### `Invalid_argument` + +Used to check if argument is valid. This exception takes a string. + + +```res example +let divide = (a, b) => + if b == 0 { + raise(Invalid_argument("Denominator is zero")) + } else { + a / b + } + +// catch error +try divide(2, 0)->Console.log catch { +| Invalid_argument(msg) => Console.log(msg) // Denominator is zero +} +``` + +```js +import * as Caml_int32 from "./stdlib/caml_int32.js"; +import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js"; + +function divide(a, b) { + if (b === 0) { + throw { + RE_EXN_ID: "Invalid_argument", + _1: "Denominator is zero", + Error: new Error() + }; + } + return Caml_int32.div(a, b); +} + +try { + console.log(divide(2, 0)); +} +catch (raw_msg){ + var msg = Caml_js_exceptions.internalToOCamlException(raw_msg); + if (msg.RE_EXN_ID === "Invalid_argument") { + console.log(msg._1); + } else { + throw msg; + } +} +``` + + + +### `Assert_failure` + +Raise when you use `assert(condition)` and `condition` is false. The arguments +are the location of the `assert` in the source code (file name, line number, column number). ```res example -exception InputClosed(string) -// later on -raise(InputClosed("The stream has closed!")) +let decodeUser = (json: JSON.t) => + switch json { + | Object(userDict) => + switch (userDict->Dict.get("name"), userDict->Dict.get("age")) { + | (Some(String(name)), Some(Number(age))) => (name, age->Float.toInt) + | _ => assert(false) + } + | _ => assert(false) + } + + +try decodeUser(%raw("{}"))->Console.log catch { +| Assert_failure(loc) => Console.log(loc) // ("filename", line, col) +} ``` + ```js -var Caml_exceptions = require("./stdlib/caml_exceptions.js"); +mport * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js"; + +function decodeUser(json) { + if (!Array.isArray(json) && (json === null || typeof json !== "object") && typeof json !== "number" && typeof json !== "string" && typeof json !== "boolean") { + throw { + RE_EXN_ID: "Assert_failure", + _1: [ + "playground.res", + 8, + 9 + ], + Error: new Error() + }; + } + if (typeof json === "object" && !Array.isArray(json)) { + var match = json["name"]; + var match$1 = json["age"]; + 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") { + return [ + match, + match$1 | 0 + ]; + } + throw { + RE_EXN_ID: "Assert_failure", + _1: [ + "playground.res", + 6, + 11 + ], + Error: new Error() + }; + } + throw { + RE_EXN_ID: "Assert_failure", + _1: [ + "playground.res", + 8, + 9 + ], + Error: new Error() + }; +} + +try { + console.log(decodeUser({})); +} +catch (raw_loc){ + var loc = Caml_js_exceptions.internalToOCamlException(raw_loc); + if (loc.RE_EXN_ID === "Assert_failure") { + console.log(loc._1); + } else { + throw loc; + } +} +``` + + -var InputClosed = Caml_exceptions.create("MyFile.InputClosed"); +### `Failure` -throw { - RE_EXN_ID: InputClosed, - _1: "The stream has closed!", - Error: new Error() -}; +Exception raised to signal that the given arguments do not make sense. This +exception takes a string as an argument. + + + +```res example +let isValidEmail = email => { + let hasAtSign = String.includes(email, "@") + let hasDot = String.includes(email, ".") + if !(hasAtSign && hasDot) { + raise(Failure("Invalid email address")) + } else { + true + } +} + + +let isValid = try isValidEmail("rescript.org") catch { +| Failure(msg) => { + Console.error(msg) + false + } +} +``` + +```js +import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js"; + +function isValidEmail(email) { + var hasAtSign = email.includes("@"); + var hasDot = email.includes("."); + if (hasAtSign && hasDot) { + return true; + } + throw { + RE_EXN_ID: "Failure", + _1: "Invalid email address", + Error: new Error() + }; +} + +var isValid; + +try { + isValid = isValidEmail("rescript.org"); +} +catch (raw_msg){ + var msg = Caml_js_exceptions.internalToOCamlException(raw_msg); + if (msg.RE_EXN_ID === "Failure") { + console.error(msg._1); + isValid = false; + } else { + throw msg; + } +} +``` + + + +### `Division_by_zero` + +Exception raised by integer division and remainder operations when their second argument is zero. + + + +```res example +// ReScript raise `Division_by_zero` if the denominator is zero +let result = try Some(10 / 0) catch { +| Division_by_zero => None +} + +Console.log(result) // None +``` + +```js +import * as Caml_int32 from "./stdlib/caml_int32.js"; +import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js"; + +var result; + +try { + result = Caml_int32.div(10, 0); +} +catch (raw_exn){ + var exn = Caml_js_exceptions.internalToOCamlException(raw_exn); + if (exn.RE_EXN_ID === "Division_by_zero") { + result = undefined; + } else { + throw exn; + } +} + +console.log(result); ```