proposal-function.sent icon indicating copy to clipboard operation
proposal-function.sent copied to clipboard

viable workaround before this lands?

Open Pyrolistical opened this issue 3 years ago • 3 comments

if you want the first .next(0.1) to work with yield, you can just wrap the generator and just drop the first .next on the floor


const skipFirstYield =
  (generator) =>
  (...parameters) => {
    const iterator = generator(...parameters)
    iterator.next()
    return iterator
  }

const adder = skipFirstYield(function* (total = 0) {
  let increment = 1
  let request
  while (true) {
    switch ((request = yield (total += increment))) {
      case undefined:
        break
      case 'done':
        return total
      default:
        increment = Number(request)
    }
  }
})


let tally = adder()
tally.next(0.1) // argument will be used!
tally.next(0.1)
tally.next(0.1)
let last = tally.next('done')
console.log(last.value) // 1.3 as desired

Pyrolistical avatar Mar 01 '22 22:03 Pyrolistical

Heck, would it be easier to spec function^ to skip the first yield instead of implementing function.sent?

then you would write

function^ adder(total = 0) {
  let increment = 1
  let request
  while (true) {
    switch ((request = yield (total += increment))) {
      case undefined:
        break
      case 'done':
        return total
      default:
        increment = Number(request)
    }
  }
}

Pyrolistical avatar Mar 01 '22 22:03 Pyrolistical

In no way would adding a ninth kind of function be easier.

ljharb avatar Mar 01 '22 22:03 ljharb

Dropping the first next is always a workaround, actually this is very close to what babel transformer do.

I don't like to add a new kind of function, but I agree we should explore alternative design, because the example codes for the use cases of this proposal always suffer some similar UX problems. Actually I tried some different alternative designs in last year, and it seem the best form is:

function *gen(...args) receive (x) { ... }

So @Pyrolistical 's code

function^ adder(total = 0) {
  let increment = 1
  let request
  while (true) {
    switch ((request = yield (total += increment))) {
      case undefined:
        break
      case 'done':
        return total
      default:
        increment = Number(request)
    }
  }
}

would become

function* adder(total = 0) receive (request) {
  let increment = 1
  while (true) {
    switch (request) {
      case undefined:
        break
      case 'done':
        return total
      default:
        increment = Number(request)
    }
    yield (total += increment)
  }
}

With some modification (drop weird "undefined" case), it could be simplified to:

function* adder(total = 0) receive (increment = 1) {
  while (true) {
    if (increment == 'done') return total
    total += Number(increment)
    yield total
  }
}

Concise and easy to understand ;-)

I would like to write more details about this alternative design in a separate issue soon.

hax avatar May 22 '22 23:05 hax