We could definitely support let? Error(err) = ... and let None = ... if that adds any value. Just a matter of swapping what’s emitted for the continue vs return case.
If you see let? as testing if fetchUser() returns an Ok then yes I’d expect the reverse to be possible too, this also aligns to what we are used to in switch pattern matching.
Happy to say this was just merged under the new concept of “experimental features” (that you will be able to turn on/off in rescript.json) and will be in the next beta that’ll be released this week
Probably I’m late to the party, but here’s the shower thought. The proposed syntax is a little bit inconsistent with promises if we look at promises, options, and results as some kind of boxes/wrappers/monadish-things that either resolve to a “good” or “bad” value. Both let? and await are basically shortcuts to express:
Unbox the value and if it’s good, assign and go on;
otherwise return the bad value putting it in the box again
In the case of promises the syntax looks like this:
let variable = <unboxing_designator> <expression>
whereas in the case of options and results it has the designator in another position:
let<unboxing_designator> variable = <expression>
With further comparison, the await is more versatile in the sense it evaluates to expression, not a statement, so the following is possible:
let something = foo(await bar(), await baz())
With everything mentioned in this thread I understand that the current implementation requires that the designator should be somewhere very close to let, but I wonder if such asymmetry is fine in the long run.
Just thinking aloud: what if unwrapping be more like await?
let bar: unit => result<string, [#errA | #errB]>
let baz: unit => result<string, [#errA | #errC]>
let foo: (string, string) => string
let myFunc = (): result<string, [#errA | #errB | #errC]> => {
let something = foo(open bar(), open baz()) // <- reusing `open` keyword, might be `try` if not followed by `{`
something
}
let updateH2Color2 = () => {
@let.unwrap
switch dollar("h2") {
| None => Error(xyz) // not sure yet how to define xyz
| Some(element) =>
@let.unwrap
switch tryMapHTMLHeadingElement(element) {
| Error(_) as x => x
| Ok(h2) =>
h2.style.color = "blue"
Some()
}
}
}
I get that xyz needs to come from somewhere, so that is challenging, I agree. But mixing option, null and nullable should be more straightforward. You could return the empty case of the last let?, I think.
In my examples, I was also grabbing data to finally mutate something. The last meaningful expression was h2.style.color = "blue". Having to return result<unit, _> didn’t add that much value. Again, this depends on the situation. This could have been: