String identity template tag

kai zhu kaizhu256 at gmail.com
Wed Dec 19 15:40:28 UTC 2018


*everything* using javascript is ultimately meant to solve a UX-workflow
problem (including js-code in servers, IoT, satellites, etc.).  if you're
so caught up in low-level js library-code that you can't see how the piece
fits/integrates into that big-picture, then you should go back to
general-purpose programming in java/c++/c#/etc.

but of course, much of industry these days prefer hiring business-oriented
programmers focused on solving UX-workflow problems rather than
general-purpose programming ones.



On Wed, Dec 19, 2018 at 6:52 AM Isiah Meadows <isiahmeadows at gmail.com>
wrote:

> 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
> contact at isiahmeadows.com
> www.isiahmeadows.com
>
> On Wed, Dec 19, 2018 at 1:33 AM kai zhu <kaizhu256 at 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 <mikesamuel at gmail.com> wrote:
> >
> > Fair enough.
> >
> > On Tue, Dec 18, 2018, 5:29 PM Isiah Meadows <isiahmeadows at 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
> >> contact at isiahmeadows.com
> >> www.isiahmeadows.com
> >> On Fri, Dec 14, 2018 at 2:55 PM Mike Samuel <mikesamuel at gmail.com>
> wrote:
> >> >
> >> >
> >> >
> >> > On Fri, Dec 14, 2018 at 2:26 PM Isiah Meadows <isiahmeadows at 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 <mikesamuel at gmail.com>
> wrote:
> >> >>>
> >> >>>
> >> >>>
> >> >>> On Fri, Dec 14, 2018 at 12:51 PM Isiah Meadows <
> isiahmeadows at 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.
> >> >>> }
> >> >>>
> >> >>>
> >> >>>
> >> >>>
> >
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20181219/43a61705/attachment-0001.html>


More information about the es-discuss mailing list