Open erights opened 4 years ago
Attn @bakkot
Attn @kriskowal
I'm aware that this is technically possible, but it is scoped narrowly to generators and to expressions which use yield
and is not something most JavaScript programmers are often exposed to. I am reluctant to reason from its example.
Rust allows returning from within an expression everywhere. It's often used to short circuit like so:
fn stuff(a: Option<u32>) -> Option<_> {
let a = if let Some(a) = a {
a
} else {
return None;
}
// do stuff with an unwrapped a
}
Given that Rust is one of the inspirations for this proposal, I think it's worth considering.
@pitaj Let's keep the general discussion of the utility of return
to #30, and leave this issue specifically for talking about the analogy to yield
.
@bakkot is your problem with return
in a do expression that it uses the return syntax or that the behaviour of return happens?
@pitaj This specific rust example seems not good (because it could be simplified as a?
and do not need return
)
Even consider similar usage in JS, it seems just ask for "return expression" like "throw expression" proposal, aka. let a1 = a ?? return null
.
@hax for Result
, that would be correct, but the try operator working for Option
is a fairly new. Regardless, the example still works as a demonstration and changing it so the try operator wouldn't work is trivial.
In case folks here aren’t familiar with Rust’s approach, here’s an example illustrating @pitaj’s point that it’s much more general than the Option
/Result
/Try
/?
behavior:
enum ArbitraryData {
Cool(String),
Neat(i32),
Rad { data: bool },
}
fn demo(data: ArbitraryData) {
let s = match data {
Cool(s) => s,
Neat(n) => n.to_string(),
Rad { data } => {
println!("demo doesn’t care about booleans!");
return;
}
};
// other stuff with `s`
}
What JS should do with do
expressions and generators specifically is indeed a separate question. And my own intuition here is that this “should” work:
function* cool() {
let x = do {
yield true;
yield false;
"look sir, droids!"
};
console.log(x); // look sir, droids!... after the first two yields.
}
While this is quite strange, and I certainly would never recommend it, intuitively it seems like this is how this should work? (I note that my own intuition matches the slides from the latest presentation.)
I agree with @chriskrycho that. It would be strange for do
expressions to exist in JS and for his example to not work.
function* cool() { let x = do { yield true; yield false; "look sir, droids!" }; console.log(x); // look sir, droids!... after the first two yields. }
One addition, eval()
doesn't support yield
. I guess it is based on the similar reason (cannot allow yield
and meaningfully prohibit return
).
So it seems we should either support both return
and yield
(and break/continue
to outer scope), or support none of them like eval
.
As https://github.com/tc39/proposal-iterator-helpers/issues/99 illustrates, if a
yield
is resumed with areturn()
, it acts as-if it is areturn
. The position advocated during the https://docs.google.com/presentation/d/14UYf30NeOd5TFZ4QJFigwBLZVotOwuQq3E-BCMIhGgk/edit#slide=id.g106f4536d9_0_109 presentation is that do expressions should allowyield
within their bodies. But notreturn
, because that would introduce a new control possibility: returning from inside an expression.The possibility is not new, since
yield
can already return from inside an expression.Prohibiting
return
alone does not accomplish this goal, since returning from inside a do expression can still happen usingyield
.