Could you bring that up in a different thread instead of driving this off-topic? Also, please don't forget that a *very* significant chunk of JS doesn't even run in a GUI environment (consider: servers, IoT, satellites, etc.).
----- Isiah Meadows cont...@isiahmeadows.com www.isiahmeadows.com On Wed, Dec 19, 2018 at 1:33 AM kai zhu <kaizhu...@gmail.com> 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. > > > 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 <mikesam...@gmail.com> wrote: > > Fair enough. > > On Tue, Dec 18, 2018, 5:29 PM Isiah Meadows <isiahmead...@gmail.com 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 >> cont...@isiahmeadows.com >> www.isiahmeadows.com >> On Fri, Dec 14, 2018 at 2:55 PM Mike Samuel <mikesam...@gmail.com> wrote: >> > >> > >> > >> > On Fri, Dec 14, 2018 at 2:26 PM Isiah Meadows <isiahmead...@gmail.com> >> > 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 <mikesam...@gmail.com> wrote: >> >>> >> >>> >> >>> >> >>> On Fri, Dec 14, 2018 at 12:51 PM Isiah Meadows <isiahmead...@gmail.com> >> >>> 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 es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss