Skip to content
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@

# 12.0.0-beta.3 (Unreleased)

#### :boom: Breaking Change

- `Result.getOrThrow` now throws a JS error instead of a `Not_found` ReScript exception. https://github.com/rescript-lang/rescript/pull/7630

#### :rocket: New Feature

- Add optional `message` argument to `Result.getOrThrow` and improve default error message. https://github.com/rescript-lang/rescript/pull/7630

#### :nail_care: Polish

- Configuration fields `bs-dependencies`, `bs-dev-dependencies` and `bsc-flags` are now deprecated in favor of `dependencies`, `dev-dependencies` and `compiler-flags`. https://github.com/rescript-lang/rescript/pull/7658
Expand Down
4 changes: 2 additions & 2 deletions lib/es6/Stdlib_Option.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@


import * as Stdlib_Error from "./Stdlib_Error.js";
import * as Stdlib_JsError from "./Stdlib_JsError.js";
import * as Primitive_option from "./Primitive_option.js";

function filter(opt, p) {
Expand All @@ -21,7 +21,7 @@ function getOrThrow(x, message) {
if (x !== undefined) {
return Primitive_option.valFromOption(x);
} else {
return Stdlib_Error.panic(message !== undefined ? message : "Option.getOrThrow called for None value");
return Stdlib_JsError.panic(message !== undefined ? message : "Option.getOrThrow called for None value");
}
}

Expand Down
9 changes: 4 additions & 5 deletions lib/es6/Stdlib_Result.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@


import * as Stdlib_JsError from "./Stdlib_JsError.js";

function getOrThrow(x) {
function getOrThrow(x, message) {
if (x.TAG === "Ok") {
return x._0;
} else {
return Stdlib_JsError.panic(message !== undefined ? message : "Result.getOrThrow called for Error value");
}
throw {
RE_EXN_ID: "Not_found",
Error: new Error()
};
}

function mapOr(opt, $$default, f) {
Expand Down
4 changes: 2 additions & 2 deletions lib/js/Stdlib_Option.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

let Stdlib_Error = require("./Stdlib_Error.js");
let Stdlib_JsError = require("./Stdlib_JsError.js");
let Primitive_option = require("./Primitive_option.js");

function filter(opt, p) {
Expand All @@ -21,7 +21,7 @@ function getOrThrow(x, message) {
if (x !== undefined) {
return Primitive_option.valFromOption(x);
} else {
return Stdlib_Error.panic(message !== undefined ? message : "Option.getOrThrow called for None value");
return Stdlib_JsError.panic(message !== undefined ? message : "Option.getOrThrow called for None value");
}
}

Expand Down
9 changes: 4 additions & 5 deletions lib/js/Stdlib_Result.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
'use strict';

let Stdlib_JsError = require("./Stdlib_JsError.js");

function getOrThrow(x) {
function getOrThrow(x, message) {
if (x.TAG === "Ok") {
return x._0;
} else {
return Stdlib_JsError.panic(message !== undefined ? message : "Result.getOrThrow called for Error value");
}
throw {
RE_EXN_ID: "Not_found",
Error: new Error()
};
}

function mapOr(opt, $$default, f) {
Expand Down
2 changes: 1 addition & 1 deletion runtime/Stdlib_Option.res
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ let getOrThrow = (x, ~message=?) =>
switch x {
| Some(x) => x
| None =>
Stdlib_Error.panic(
Stdlib_JsError.panic(
switch message {
| None => "Option.getOrThrow called for None value"
| Some(message) => message
Expand Down
12 changes: 6 additions & 6 deletions runtime/Stdlib_Option.resi
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Option.forEach(None, x => Console.log(x)) // returns ()
let forEach: (option<'a>, 'a => unit) => unit

/**
`getExn(opt, ~message=?)` returns `value` if `opt` is `Some(value)`, otherwise raises an exception with the message provided, or a generic message if no message was provided.
`getExn(opt, ~message=?)` returns `value` if `opt` is `Some(value)`, otherwise throws an exception with the message provided, or a generic message if no message was provided.

```rescript
Option.getExn(Some(3)) == 3
Expand All @@ -82,20 +82,20 @@ switch Option.getExn(None) {
}

switch Option.getExn(None, ~message="was None!") {
| exception _ => assert(true) // Raises an Error with the message "was None!"
| exception _ => assert(true) // Throws a JsError with the message "was None!"
| _ => assert(false)
}
```

## Exceptions

- Raises an error if `opt` is `None`
- Throws an error if `opt` is `None`
*/
@deprecated("Use `getOrThrow` instead")
let getExn: (option<'a>, ~message: string=?) => 'a

/**
`getOrThrow(opt, ~message=?)` returns `value` if `opt` is `Some(value)`, otherwise raises an exception with the message provided, or a generic message if no message was provided.
`getOrThrow(opt, ~message=?)` returns `value` if `opt` is `Some(value)`, otherwise throws an exception with the message provided, or a generic message if no message was provided.

```rescript
Option.getOrThrow(Some(3)) == 3
Expand All @@ -106,14 +106,14 @@ switch Option.getOrThrow(None) {
}

switch Option.getOrThrow(None, ~message="was None!") {
| exception _ => assert(true) // Raises an Error with the message "was None!"
| exception _ => assert(true) // Throws a JsError with the message "was None!"
| _ => assert(false)
}
```

## Exceptions

- Raises an error if `opt` is `None`
- Throws an error if `opt` is `None`
*/
let getOrThrow: (option<'a>, ~message: string=?) => 'a

Expand Down
10 changes: 8 additions & 2 deletions runtime/Stdlib_Result.res
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
type t<'res, 'err> = result<'res, 'err> = Ok('res) | Error('err)

let getOrThrow = x =>
let getOrThrow = (x, ~message=?) =>
switch x {
| Ok(x) => x
| Error(_) => throw(Not_found)
| Error(_) =>
Stdlib_JsError.panic(
switch message {
| None => "Result.getOrThrow called for Error value"
| Some(message) => message
},
)
Comment on lines -29 to +35
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess technically this is a breaking change. But I don't think we've stopped because of this before (going from exception to general JS error).

Copy link
Member Author

@mediremi mediremi Jul 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a note to the changelog about this breaking change 👍

}

let getExn = getOrThrow
Expand Down
22 changes: 16 additions & 6 deletions runtime/Stdlib_Result.resi
Original file line number Diff line number Diff line change
Expand Up @@ -48,33 +48,43 @@ query operation:
type t<'res, 'err> = result<'res, 'err> = Ok('res) | Error('err)

/**
`getExn(res)`: when `res` is `Ok(n)`, returns `n` when `res` is `Error(m)`, raise an exception
`getExn(res, ~message=?)` returns `n` if `res` is `Ok(n)`, otherwise throws an exception with the message provided, or a generic message if no message was provided.

```res example
Result.getExn(Result.Ok(42)) == 42

switch Result.getExn(Error("Invalid data")) {
| exception Not_found => assert(true)
| exception _ => assert(true)
| _ => assert(false)
}

switch Result.getExn(Error("Invalid data"), ~message="was Error!") {
| exception _ => assert(true) // Throws a JsError with the message "was Error!"
| _ => assert(false)
}
```
*/
@deprecated("Use 'getOrThrow' instead")
let getExn: result<'a, 'b> => 'a
let getExn: (result<'a, 'b>, ~message: string=?) => 'a

/**
`getOrThrow(res)`: when `res` is `Ok(n)`, returns `n` when `res` is `Error(m)`, raise an exception
`getOrThrow(res, ~message=?)` returns `n` if `res` is `Ok(n)`, otherwise throws an exception with the message provided, or a generic message if no message was provided.

```res example
Result.getOrThrow(Result.Ok(42)) == 42

switch Result.getOrThrow(Error("Invalid data")) {
| exception Not_found => assert(true)
| exception _ => assert(true)
| _ => assert(false)
}

switch Result.getOrThrow(Error("Invalid data"), ~message="was Error!") {
| exception _ => assert(true) // Throws a JsError with the message "was Error!"
| _ => assert(false)
}
```
*/
let getOrThrow: result<'a, 'b> => 'a
let getOrThrow: (result<'a, 'b>, ~message: string=?) => 'a

/**
`mapOr(res, default, f)`: When res is `Ok(n)`, returns `f(n)`, otherwise `default`.
Expand Down
8 changes: 4 additions & 4 deletions tests/analysis_tests/tests/src/expected/Completion.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2597,14 +2597,14 @@ Path g
"label": "Result.getExn",
"kind": 12,
"tags": [1],
"detail": "result<'a, 'b> => 'a",
"documentation": {"kind": "markdown", "value": "Deprecated: Use 'getOrThrow' instead\n\n\n `getExn(res)`: when `res` is `Ok(n)`, returns `n` when `res` is `Error(m)`, raise an exception\n\n ```res example\n Result.getExn(Result.Ok(42)) == 42\n \n switch Result.getExn(Error(\"Invalid data\")) {\n | exception Not_found => assert(true)\n | _ => assert(false)\n }\n ```\n"}
"detail": "(result<'a, 'b>, ~message: string=?) => 'a",
"documentation": {"kind": "markdown", "value": "Deprecated: Use 'getOrThrow' instead\n\n\n `getExn(res, ~message=?)` returns `n` if `res` is `Ok(n)`, otherwise throws an exception with the message provided, or a generic message if no message was provided.\n\n ```res example\n Result.getExn(Result.Ok(42)) == 42\n \n switch Result.getExn(Error(\"Invalid data\")) {\n | exception _ => assert(true)\n | _ => assert(false)\n }\n\n switch Result.getExn(Error(\"Invalid data\"), ~message=\"was Error!\") {\n | exception _ => assert(true) // Throws a JsError with the message \"was Error!\"\n | _ => assert(false)\n }\n ```\n"}
}, {
"label": "Result.getOrThrow",
"kind": 12,
"tags": [],
"detail": "result<'a, 'b> => 'a",
"documentation": {"kind": "markdown", "value": "\n `getOrThrow(res)`: when `res` is `Ok(n)`, returns `n` when `res` is `Error(m)`, raise an exception\n\n ```res example\n Result.getOrThrow(Result.Ok(42)) == 42\n \n switch Result.getOrThrow(Error(\"Invalid data\")) {\n | exception Not_found => assert(true)\n | _ => assert(false)\n }\n ```\n"}
"detail": "(result<'a, 'b>, ~message: string=?) => 'a",
"documentation": {"kind": "markdown", "value": "\n `getOrThrow(res, ~message=?)` returns `n` if `res` is `Ok(n)`, otherwise throws an exception with the message provided, or a generic message if no message was provided.\n\n ```res example\n Result.getOrThrow(Result.Ok(42)) == 42\n \n switch Result.getOrThrow(Error(\"Invalid data\")) {\n | exception _ => assert(true)\n | _ => assert(false)\n }\n\n switch Result.getOrThrow(Error(\"Invalid data\"), ~message=\"was Error!\") {\n | exception _ => assert(true) // Throws a JsError with the message \"was Error!\"\n | _ => assert(false)\n }\n ```\n"}
}, {
"label": "Result.getOr",
"kind": 12,
Expand Down