purify icon indicating copy to clipboard operation
purify copied to clipboard

Are the `EitherAsync` methods `.map` and `.chain` deterministic

Open Duncan3142 opened this issue 11 months ago • 5 comments

Are the EitherAsync methods .map and .chain deterministic, when the callback throws an error?

Having run the following code to test behaviour,

const e1 = await EitherAsync(() => Promise.resolve(true))
  .map(async (b) => { throw new Error('Panic') }).run()

e1.isLeft() // true
e1.extract() // Error('Panic')

const e2 = await EitherAsync(() => Promise.resolve(true))
  .chain(async (b) => { throw new Error('Panic') }).run()

e2.isLeft() // true
e2.extract() // Error('Panic')

it appears exceptions will be wrapped in a Left. This is desirable behaviour, but I can't see it in the docs.

If it is deterministic, I'm happy to open a PR to add examples to the docs.

Duncan3142 avatar Mar 25 '25 10:03 Duncan3142

On a related point, when the callbacks of the Either methods .map and .chain throw an error, they're not caught and transformed to a Left by purify-ts

Duncan3142 avatar Mar 25 '25 10:03 Duncan3142

Yes, this is desirable behaviour. It's not part of the docs, unfortunately, you are correct.

On a related point, when the callbacks of the Either methods .map and .chain throw an error, they're not caught and transformed to a Left by purify-ts

EitherAsync.map swallowing exceptions is 10% design choice and 90% just because EitherAsync is a wrapper on top of Promise so it's unavoidable. In an ideal world both methods would not catch errors.

gigobyte avatar Mar 27 '25 18:03 gigobyte

Thanks for clarifying. Would you like me to a create a PR, to document the behaviour of EitherAsync when callbacks throw?

Duncan3142 avatar Mar 27 '25 18:03 Duncan3142

Or perhaps it's better to mandate in the docs that the user ensures callbacks don't throw?

Duncan3142 avatar Mar 27 '25 18:03 Duncan3142

I think both, users should know about this behaviour, but shouldn't abuse it.

gigobyte avatar Mar 31 '25 08:03 gigobyte