DEV Community

Discussion on: How to handle a nodeback in ReasonML

Collapse
 
idkjs profile image
Alain

Greetings, sir. I tossed this code into a file and got this error:

  /Users/prisc_000/working/NATIVE/bloody-authenticator/src/NodeBack.re 14:30-33

  12 ┆ nodeback(
  13 ┆   fun
  14 ┆   | Error(err) => raise({j|$err|j}) // Can't access data in this branc
       h
  15 ┆   | Ok(data) => Js.log(data),
  16 ┆ ) // Can't access err in this branch

  This has type:
    string
  But somewhere wanted:
    exn

code i copied:

let nodeback = f =>
  (. err, result) =>
    switch (err, result) {
    | (Some(err), None) => f(Js.Result.Error(err))
    | (None, Some(result)) => f(Ok(result))
    // Throw if APIs break nodeback 'guarantee':
    | _ => invalid_arg("Nodeback arguments invalid")
    };

Node.Fs.readFileSync(
  "/etc/passwd",
  nodeback(
    fun
    | Error(err) => raise({j|$err|j}) // Can't access data in this branch
    | Ok(data) => Js.log(data),
  ) // Can't access err in this branch
);

How would I fix that?

Collapse
 
yawaramin profile image
Yawar Amin • Edited

Hi Alain, somehow I completely missed your comment here. Thanks for pointing out this error. Mistake on my part, can be fixed by swapping out the raise with failwith: | Error(err) => failwith({j|$err|j}) // Can't access data in this branch. raise expects something of type exn, but we are calling it with a string. We should use failwith instead which does take a string.

After that fix there is a second error, because the Node.Fs.readFileSync function doesn't actually take a nodeback. In my example I used a hypothetical function Node.Fs.readFile. I say hypothetical because it's not bound in the libraries shipped with BuckleScript, but of course fs.readFile is a real NodeJS function and you could write a binding fairly easily: nodejs.org/dist/latest-v10.x/docs/...

Anyway here's a full working example:

[@bs.module "fs"]
external readFile:
  (
    ~path: string,
    ~options: {
                .
                "encoding": option(string),
                "flag": option(string),
              }
                =?,
    (. Js.Nullable.t('err), Js.Nullable.t(string)) => unit
  ) =>
  unit =
  "";

let nodeback = f =>
  (. err, result) =>
    switch (Js.Nullable.(toOption(err), toOption(result))) {
    | (Some(err), None) => f(Js.Result.Error(err))
    | (None, Some(result)) => f(Ok(result))
    // Throw if APIs break nodeback 'guarantee':
    | _ => invalid_arg("Nodeback arguments invalid")
    };

let readFile = (~flag=?, ~path, f) =>
  readFile(
    ~path,
    ~options={"encoding": Some("utf8"), "flag": flag},
    nodeback(f),
  );

let test = () =>
  readFile(
    ~path="/etc/passwd",
    fun
    | Ok(data) => Js.log(data) // Can't access err in this branch
    | Error(err) => failwith({j|$err|j}) // Can't access data in this branch
  );
Collapse
 
idkjs profile image
Alain

Thanks for taking the time, sir. I can't get this to run for whatever reason. I got this gist to run, gist.github.com/idkjs/c48dda9f1dba... but when i got to apply the concept, i keep running into problems. Even searched through your book! I will keep at it. Peace to you.

Thread Thread
 
yawaramin profile image
Yawar Amin

My apologies, I should have tested that example more thoroughly. I've now updated my previous comment with a really working code sample. You can run it like this:

$ bsb
$ node
> const {test} = require('./src/Main.bs')
> test()