May yield* send the last yield value?
Opened this issue · 7 comments
YieldExpression:yield*AssignmentExpression
...
4. Let received be NormalCompletion(undefined).
May it update to 4. Let received be NormalCompletion(LastYieldValue)
so we can satisfy:
function *g1() {
yield function.sent
}
function *g2() {
yield* g1()
}
g2().next(42) // => {value:42}
But allow delegate generator access the last yield value also have dark side:
function* service() {
const token = function.sent
if (auth(token)) {
yield* serviceOf3rdParty()
}
}
const serv = service()
serv.next('my-secret-token')
I'd rather not see that happen by default given the second case, perhaps a variant of yield*
or a function that forwards a value e.g.:
function* g2() {
yield** g1()
}
// Or just a function (which can even be written in userland)
function* g2() {
yield* withInitial(function.sent, g1())
}
Consider the common use cases (if i can deal with the value of function.sent
, process it in current generator, or delegate to sub generator), I think we need a ergonomic way to pass the value to sub generators. Besides new syntax like yield **g()
, another possibility is changing function.sent
to a function so we can have rich semantic :
function *g2() {
// function.sent() seems not a proper name, so let's use function.readValue()
const x = function.readValue()
if (i_can_deal_with_it()) {
...
} else { // delegate to sub generator
yield *g1() // g1 can read x via function.readValue()
}
}
For the case of previous dark side example,
function* service() {
// function.readValue(true) means the value is consumed
// calling function.readValue() again before next next(v) would throw
const token = function.readValue(true)
if (auth(token)) {
yield* serviceOf3rdParty() // so serviceOf3rdParty can't see token
}
}
const serv = service()
serv.next('my-secret-token')
It makes no sense to be to have it be "consumeable". It's a single static value, like a const
; you can access it as many times as you need. yield *
delegates control to an iterator, not a generator, so i don't think it's sensible or possible to pass it along.
It makes no sense to be to have it be "consumeable".
I'm not sure whether "consumable" is good or bad, but it's really consuming values from next(value)
in function.sent
usage.
It's a single static value, like a
const
;
It's not like const
, every time after yield
the value would change.
you can access it as many times as you need.
This is just current semantic, but I think it's not a hard requirement. As I understand, the only core requirement uptonow is providing a way to get the first value sent by next()
.
yield *
delegates control to an iterator, not a generator, so i don't think it's sensible or possible to pass it along.
This issue is really about that. yield * g()
will also delegate next(value)
except the first call. Actually other proposals like iterator helpers also keep delegate next(value)
. So it 's of coz "sensible" or "possible" to pass it along, for example via userland code like yield* withInitial(function.sent, g1())
though it's not very ergonomic.
The essential problem of this issue is, currently yield* g
will always start g with g.next(undefined)
, changing that to g.next(function.sent)
(if keep the syntax untouched) is theoretically a breaking change, for example, code like below will break.
function iter() {
return {
[Symbol.iterator]() { return this },
next(v) {
// assume client code never send undefined after first call
if (v === undefined) { // first call,
// do some stuff for setup
} else {
// process
}
}
}
}
It's not like const, every time after yield the value would change.
you're right, my mistake - it's more like a live binding, as if from an import.
theoretically a breaking change
That's true, but if you design an iterator like that, anyone could break it very easily (including, with yield undefined
) so i don't think that's a reasonable thing for us to be concerned about.
so i don't think that's a reasonable thing for us to be concerned about.
I'm not sure about that. If a big site had such code (of coz I hope it would never happen), land such change would "break the web" anyway. 😅