> I could go with an iterator equivalent, but I'd like to defer that to
> the seemingly-planned "iterlib" thing that's been considered since
> before ES2015 was released.

i'm against iterator-based design-patterns and libraries, as they lack a clear 
fit in most javascript solutions.  the vast majority of looping in UX-workflows 
(javascript’s primary problem-domain) are over [serializable] JSON 
lists/dicts/strings, where Array/Object/String looping-methods will suffice.

all other use-cases are uncommon/complicated enough that custom for/while loops 
are usually better suited than custom-iterators.

-kai



> On 18 Dec 2018, at 16:42, Mike Samuel <[email protected]> wrote:
> 
> Fair enough.
> 
> On Tue, Dec 18, 2018, 5:29 PM Isiah Meadows <[email protected] 
> <mailto:[email protected]> wrote:
> I could go with an iterator equivalent, but I'd like to defer that to
> the seemingly-planned "iterlib" thing that's been considered since
> before ES2015 was released. Something that works with arrays is good
> enough for now.
> 
> BTW, your `ziperator` isn't really the same as my `Array.interpolate`
> (which is better named `Array.interleave`). It needs to be this:
> 
> ```js
> function *ziperator(...iters) {
>     for (let i = 0; i < iters.length; i++) {
>         iters[i] = iters[i][Symbol.iterator]()
>     }
>     while (true) {
>         for (let i = 0; i < iters.length; i++) {
>             const {done, value} = iters[i].next()
>             if (done) return undefined
>             yield value
>         }
>     }
> }
> ```
> 
> The optimized version is pretty straightforward (using private fields
> + methods here):
> 
> ```js
> function ziperator(...iters) { return new InterleavedIterator(iters) }
> 
> class InterleavedIterator {
>     #iters, #index
>     constructor(iters) { this.#iters = iters; this.#index = 0 }
>     [Symbol.iterator]() { return this }
>     next(value) { return this.#invoke("next", value) }
>     throw(value) { return this.#invoke("throw", value) }
>     return(value) { return this.#invoke("return", value) }
>     #invoke(method, value) {
>         if (this.#iters == null) return {done: true, value: undefined}
>         const index = this.#index
>         this.#index = (index + 1) % this.#iters.length
>         const {done, value} = this.#iters[index][method](value)
>         if (done) this.#iters = undefined
>         return {done, value}
>     }
> }
> ```
> 
> -----
> 
> Isiah Meadows
> [email protected] <mailto:[email protected]>
> www.isiahmeadows.com <http://www.isiahmeadows.com/>
> On Fri, Dec 14, 2018 at 2:55 PM Mike Samuel <[email protected] 
> <mailto:[email protected]>> wrote:
> >
> >
> >
> > On Fri, Dec 14, 2018 at 2:26 PM Isiah Meadows <[email protected] 
> > <mailto:[email protected]>> wrote:
> >>
> >> The main difference with that loop is that it's generalized to any number 
> >> of arrays, not just two with the second array having length one less than 
> >> the first. Otherwise, it'd look exactly the same. BTW, I like this route 
> >> (`Array.interleave`) better since it doesn't have to result in just a 
> >> single string result - it could just be an array of strings plugged into 
> >> some API instead, or it could be procedurally streamed out in chunks.
> >
> >
> > Fair enough.
> > If you're not looking for something template tag specific then a simple zip 
> > over iterators should do it?
> >
> > function *ziperator(iterators) {
> >     let progressed;
> >     do {
> >         progressed = false;
> >         for (let iterator of iterators) {
> >             for (let element of iterator) {
> >                 yield element;
> >                 progressed = true;
> >                 break;
> >             }
> >         }
> >     } while (progressed);
> > }
> >
> > console.log(Array.from(ziperator([ ['a', 'b', 'c'][Symbol.iterator](), [1, 
> > 2][Symbol.iterator]() ])).join(''));
> > // -> a1b2c
> >
> > (but optimized :)
> >
> >
> >
> >>
> >> On Fri, Dec 14, 2018 at 14:04 Mike Samuel <[email protected] 
> >> <mailto:[email protected]>> wrote:
> >>>
> >>>
> >>>
> >>> On Fri, Dec 14, 2018 at 12:51 PM Isiah Meadows <[email protected] 
> >>> <mailto:[email protected]>> wrote:
> >>>>
> >>>> I'll point out Kai could be on to something, although I disagree `zip` 
> >>>> would be the right abstraction. Maybe `Array.interleave(...arrays)`? You 
> >>>> could do `Array.interleave(template, args).map(String).join("")` for 
> >>>> similar effect, and it'd be more generally useful.
> >>>>
> >>>> The key here is that iteration would stop after the index hits any 
> >>>> array's length, so it'd be polyfilled kinda like this:
> >>>>
> >>>> ```js
> >>>> Array.interpolate = (...args) => {
> >>>>     let ret = []
> >>>>     let lengths = []
> >>>>     let count = 0
> >>>>     for (let i = 0; i < args.length; i++) {
> >>>>         lengths[i] = args[i].count
> >>>>     }
> >>>>     for (let index = 0; ; index++) {
> >>>>         for (let i = 0; i < args.length; i++) {
> >>>>             if (index === lengths[i]) return ret
> >>>>             ret[count++] = args[i][index]
> >>>>         }
> >>>>     }
> >>>> }
> >>>> ```
> >>>>
> >>>> (This could be optimized, though.)
> >>>
> >>>
> >>> As a data point, something like this loop appears in most of the template 
> >>> tags I've written but
> >>> it's never had these precise semantics so I didn't bother putting it into 
> >>> template-tag-common.
> >>>
> >>> That library makes it easy to split the operation of a template tag into 
> >>> 3 stages:
> >>> 1. An optional configuration stage accessed by calling the template tag 
> >>> as a regular function: mytag({ /* options */)`...`
> >>> 2. Static analysis over the strings.   This is memoized.
> >>> 3. Computing a result from (options, strings, results of step 2, 
> >>> interoplated values)
> >>>
> >>> The final loop (step 3) in the template tags I maintain tends to looks 
> >>> like
> >>>
> >>> function computeResult(options, staticState /* from step 2 */, strings, 
> >>> ...values) {
> >>>   let n = values.length;  // Could do Math.max(strings.length - 1, 
> >>> values.length);
> >>>   let result = strings[0];  // Usually strings.raw
> >>>   for (let i = 0; i < n;) {
> >>>     const interpolatedValue = f(options, staticState[i], values[i]);
> >>>     // Sometimes code here looks backwards at the result to see if it 
> >>> needs to avoid token-merging hazards.
> >>>     result += interpolatedValue;
> >>>     result += strings[++i];
> >>>   }
> >>>   return wrapResult(result);  // Produce a value of a type that 
> >>> encapsulates the tag's security guarantees.
> >>> }
> >>>
> >>>
> >>>
> >>>

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to