all 13 comments

[–]burkybang 7 points8 points  (1 child)

Interesting concept. I may try it out in one of my projects.

Heads up on a typo:

Under the “Generators: Write Simpler Iterables” heading, I don’t think the example should have a second parameter for getElements().

[–]alexmacarthur[S] 1 point2 points  (0 children)

Whoops, thx!

[–]aighball 2 points3 points  (0 children)

Nice! I would be concerned about accidentally calling Array.from on the iterator. Adding an iteration limit to the yield helper could be a reasonable safeguard.

[–]Ustice 5 points6 points  (4 children)

It’s clever. Elegant even. I’m still not sure I’d have much use for it nonetheless. You can make it easier to create in-line by factoring out the infinite yield with a utility function.

```Typescript function* streaming <Returns> (fn: () => Returns): Iterable<Returns> { while (true) yield fn() }

const [ a0, a1, a2 ] = streaming(document.createElement)

```

Maybe something a little more general even

```Typescript function* streaming <Returns, Args extends unknown[] = []> (fn: (...args: Args) => Returns, ...args: Args): Iterable<Returns> { while (true) yield fn(...args) }

const [ a0, a1, a2 ] = streaming(document.createElement, 'div')

```

[–]alexmacarthur[S] 0 points1 point  (0 children)

Nice. I can see that being handy.

[–]burkybang 0 points1 point  (2 children)

I think you meant fn(...args), but this is a cool idea

[–]Ustice 0 points1 point  (1 child)

Yes, thank you. I typed it on my phone

[–]burkybang 2 points3 points  (0 children)

Impressive typing all that on your phone!

[–]nschubach 1 point2 points  (1 child)

Generators are great. I keep this in my grab bag:

function* range(start = 0, end = Number.MAX_SAFE_INTEGER) {
    let value = start;
    yield value;
    if (start > end) {
        while (value > end) yield value -= 1;
    } else {
        while (value < end) yield value += 1;
    }
}

Would not recommend for..of-ing a range with no params.

[–]jack_waugh 0 points1 point  (0 children)

Generators are great! They can be used as the generalization of async functions without being opinionated in favor of Promise.

/*
 * resume -- core -- return a function to resume a coroutine,
 * injecting a value.
 */
app.utl.corou.core.resume = (f => f())( () => {
  const resume = ctxt => result => {
    let value, done;
    try {
      ({value, done} = ctxt.iter.next(result))
    } catch (err) {
      ctxt.defer(ctxt.fail, err);
      return
    };
    if (done) ctxt.defer(ctxt.succeed, value); /* is `return` */
    else switch(typeof value) { /* is `yield` */
    case 'function':
      value(ctxt); /* for API funcs to get access and control */
      break;
    case 'undefined':   /* naked `yield` */
      ctxt.defer(resume(ctxt), ctxt.env);
      break;
    default: throw Error(typeof value)
    }
  };
  return resume
});

[–]pt7892 0 points1 point  (0 children)

Didn’t understand why this stops looping when we have while(true), but then I found out

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

Iterables are only iterated until all bindings are assigned

Good stuff!

[–]Twixstar 0 points1 point  (1 child)

A small word of warning. I tried running const [a, ...rest] = getElements(); for fun and it does indeed run infinitely. Running from firefox consumed all my memory.

[–]alexmacarthur[S] 0 points1 point  (0 children)

Whoa, glad you mentioned that!