(implementation for js.Promise)[was: parameterize error type]
aappddeevv opened this issue · 8 comments
When using data structures in scala.js, such as js.Promise, the error type when using javascript code is derived from Any--it does not need to derive from Exception/Throwable. Is there any way to keep everything easy but parameterize on the error type as well?
Some very quick ideas (will think in details later)
-
will. throw "NotThrowable" will be legal scala-js code ?
-
let we have external js.Promise
In such case,
CpsTryMonad.restore(promse)(handler)
can create JsThrowableWrapper wich wrap non-throwable error in promise and pass it to handler wrapped.
Yes, CpsTryMonad.restore
is the only place, where we see external Promise.
[ https://github.com/rssh/dotty-cps-async/blob/350b9a7a4a34430c6b2115052e070fc3570c974d/shared/src/main/scala/cps/CpsMonad.scala#L33 ]
So, wrap it there will be enough to keep the scala side happy.
Another question - let us want to reject a promise with a non-exceptional error type. How we pass rejection to the js side?
if via native Promise.reject - plain types will work. If we want to throw .... => throw will compile to CpsTryMonad.error where we can unwrap Throwable wrapper.
So, unwrap plain error from the throwable wrapper in CpsTryMonad.error
From js side, looks like we need to keep Scala Throwable in some special wrapper object.
I implemented CpsTryMonad. I'll write some tests and code to try some different things so we have a baseline set of facts.
Scala.js actually wraps javascript exceptions but only under specific situations. https://www.scala-js.org/doc/interoperability/exceptions.html. And that link really applies to try/catch vs js.Promise, which I have found different behaviors.
Cool !.
About js interoperability: thinking about exception path: Scala[1] -> JS[2] -> Scala[3] Let we throw scala exception, than handle this on Js side then pass back to Scala. In the naive understanding, the original exception's described policy will pass the exception from [1] to [3] wrapped.
It looks like now I know too little about scalajs implementation to deduce the behavior—[Maybe scalajs already mark scala object with some runtime tags, which should allow escape wrapping]. Interesting - need to learn.
Aga. discovered that scala isInstanceOf mapped to javascript instanceof (which check constructor property in prototype chain).
so, existing converters should work good:
https://github.com/scala-js/scala-js/blob/317282ed451cc5c6dc986c81b0af061227f7be1a/library/src/main/scala/scala/scalajs/runtime/package.scala#L21
In JS world a value of any type can be thrown. I'll work on those examples to highlight every case.
Also interesting, that in javascript API is impossible to create Promise[Promise[A]]. (or Promise[B <: Thrennable] ) by design. This will be automatically flattened during construction.
So, we can't implement a direct CpsMonad[Promise] without breaking a contract. Instead, we can teach await
to work with non-monadic but 'awaitable' structures.
It was half of the story. The next half is to provide a boilerplate-free way of exploring futures as promises to javascript/typescript.