ReasonML Exception Handling
One thing I found it is kinda understandable and not understandable at the same time is the lack of articles, examples or anything that mentioned how to handle an exception in ReasonML. By nature, I don’t see much use of exception writing code in ReasonML. However, It can’t be avoided when we want to interop with JavaScript.
Since I can’t find the formal grammar on ReasonML exception, I will fall back to OCaml exception definition.
in Ocaml, Exception is merely an extensible variant of type
exn
To handle an exception in OCaml, we can use try/with
construct which resemble a pattern matching:
try <expr> with
| <pat1> -> <expr1>
| <pat2> -> <expr2>
...
In ReasonML, we use the following clause:
try (<expr>) {
| <pat1> => <expr1>
| <pat2> => <expr2>
...
}
expr
is evaluated and checked. If there is an exception thrown, then it tries to match the given pattern(Keep in mind that it is a normal pattern matching with the constraint of built-in type exn
). Else, the result will be an evaluation of expr
. The following code is an example of how to use exception in ReasonML syntax.
try (f) {
| SomeExn => doSomething()
| AnotherExn(value) => doSomethingWith(value)
...
}
The pattern in the clause must be a type of exn
only. We will show later that this keyword can be replaced with switch
of exception type.
Define exception type using exception
keyword
To work with exceptions, we must know how to define it first. It is simple as defining a type. In fact,exception
is syntactic sugar to add a new type to exn.
Consider the following code:
type exn +=
| MyError;exception MyAnotherError;
The first two lines are to add the new type called MyError
using the extensible variant syntax. The line below does the same thing but using exception
keyword. As we can see from the JavaScript’s counterpart:
var MyError = Caml_exceptions.create("MyError");var MyAnotherError = Caml_exceptions.create("MyAnotherError");
The exception
definition is to define any exception we want to give a meaning in our program. However, in order to deal with exceptions from JavaScript, we must handle Js.Exn.Error(t)
Handling Exception from JavaScript side
Most of the exceptions raised from JavaScript side will become a value of type Js.Exn.Error(t)
. Let assume the scenario, we want to use a JavaScript function which can throw an exception.
exports.func = function(x) {
throw new Error("My Js Error");
return x;
}
We need to handle this exception properly.
[@bs.module "./test.js"] external func: (string) => string = "func";let result = try(func("test"){
|Js.Exn.Error(err) => Js.Exn.message(err)
|> Js.Option.getWithDefault("Some Js Error");""
|x => failwith(x);"Other Error"
}
The code above imports a functionfunc
which is a JavaScript function and use the construct try
to test if it throws an exception. If the exception throwing is of type Js.Exn.Error
, we will use Js.Exn.message
to extract the error message. Otherwise, it will failwith
any other type of exceptions.
Note that the result of try
must be of the same type of func
result, in this case, a string
.
To see why, let’s unfold try
into normal pattern matching. We can achieve the same behavior using a pattern matching as follows:
[@bs.module "./test.js"] external func: (string) => string = "func";let result = switch(func("test")){
| exception(Js.Exn.Error(err)) => Js.Exn.message(err)
|> Js.Option.getWithDefault("Some Js Error");""
| exception(x) => failwith(x);"Other Error"
| value => value
}
Now things make more sense because value => value
suggests that the type of this evaluation should return the value
of the type of func
result.
Hope this is useful when you are trying to google for ReasonML Exception Handling. That’s the whole reason while I wrote this. Feel free to leave me any comment or suggestion. Thanks!