es-discuss@mozilla.org
ts 1 > > ``` > > > > In Augusto’s example, you would have your choice of object passing or > variable passing: > > > > ```js > > function foo(ref value) { > value = 'foo'; > } > > function second(source) { > > { > > let { ref value } = source; // NOTE `value` is a `Reference` object here > console.log(typeof value); // object > foo(value); > > } > > > > // The above would be the same as this > > { > let value = ref source.value; // `value` is a `Reference` object here > > console.log(typeof value); // object > foo(value); > } > > } > > > > second({ value: "bar" }); > > ``` > > > > I’m still considering the destructuring side of things. Whether you are > creating a `Reference` or dereferencing it is clear for some patterns: > > > > ```js > // (a) `ref` Destructuring Targets > > // dereferences `obj.x` if `obj.x` is a `Reference` > > let { x: ref x } = obj; > > // This is equivalent to the following: > > let ref x = obj.x; // Probably not what you want… > > > > > > // (b) `ref` Destructuring Bindings > > // creates a `Reference` for `obj.x` and stores it in `x`, so `x` is a > reified `Reference`. > > let { ref x: x } = obj; > > > > // This is equivalent to the following: > > let x = ref obj.x; // Probably not what you want either… > > > > > > // (c) `ref` Destructuring Targets **and** Bindings > > // Create a `Reference` for `obj.x` and dereference it in `x`: > > let { ref x: ref x } = obj; > > // This is equivalent to the following: > let ref x = ref obj.x; // Probably what you wanted > ``` > > However, this is less clear for shorthand destructuring assignments or > array destructuring: > > > > ```js > > let { ref x } = obj; // did you mean (a), (b), or (c) above? > > let [ref x] = ar; // did you mean (a), (b), or (c) above? > > ``` > > > > In these two examples, you **probably** want (c), but there are valid > reasons for wanting (a) or (b) as well. The explainer for the proposal > currently chooses (a), but I’ve been reconsidering. None of this is set in > stone (since this proposal isn’t even at Stage 1 yet), and I’m open to > suggestions and discussion on the issue tracker. > > > > Ron > > > > *From:* es-discuss * On Behalf Of *Andrea > Giammarchi > *Sent:* Thursday, March 4, 2021 12:43 AM > *To:* Augusto Moura > *Cc:* es-discuss > *Subject:* [EXTERNAL] Re: Destructuring by &reference > > > > > How will you prevent the passing of the object down the pipe? > > > > ```js > > const downThePipe = ({&source}) => { > > // you can read source > > source; > > // you can set source > > source = 'blah'; > > // you can't know where source comes from > > // but you could propagate that reference further > > evenFurtherDown({&source, any: 'value'}, Math.random()); > > }; > > > > downThePipe({ > > secret: 'nothing out there can reach me', > > get source() { 'this object'; }, > > set source(value) { > > console.log('hello', value, this.secret); > > } > > }); > > ``` > > > > You can pass objects already in JS so this changes nothing in terms of > logic, except the callback has a way to signal reactive properties or > retrieved methods. > > > > Any boilerplate with Proxies would be slower and more convoluted, so this > syntax simplieis all the code you wrote via an explicit intent: the > callback would like to invoke, or update an accessor, of the given object, > without holding, or having, the whole object in its scope. > > > > I hope this explains a bit better why I think this feature would be > extremely cool. Polyfills won't need to do much, code remains short and > clean, accessors/reactive properties becomes instantly clear (they say > accessors are a footgun, here we're flagging these for better awareness) > and methods can be invoked with the right context too, without needing > whole objects references around. > > > > > > On Wed, Mar 3, 2021 at 9:03 PM Augusto Moura > wrote: > > > that's basically the entirety of the syntax sugar proposals since > ES2015, right? > > Definitely no, but talking about the syntax additions since ES2015, they > are in one or more of the categories below: > - avoid known footguns in the language (arrow functions and lexical this, > classes and prototype, let/const and block scoping, nullish coalescing > operator
es-discuss@mozilla.org
> How will you prevent the passing of the object down the pipe? ```js const downThePipe = ({&source}) => { // you can read source source; // you can set source source = 'blah'; // you can't know where source comes from // but you could propagate that reference further evenFurtherDown({&source, any: 'value'}, Math.random()); }; downThePipe({ secret: 'nothing out there can reach me', get source() { 'this object'; }, set source(value) { console.log('hello', value, this.secret); } }); ``` You can pass objects already in JS so this changes nothing in terms of logic, except the callback has a way to signal reactive properties or retrieved methods. Any boilerplate with Proxies would be slower and more convoluted, so this syntax simplieis all the code you wrote via an explicit intent: the callback would like to invoke, or update an accessor, of the given object, without holding, or having, the whole object in its scope. I hope this explains a bit better why I think this feature would be extremely cool. Polyfills won't need to do much, code remains short and clean, accessors/reactive properties becomes instantly clear (they say accessors are a footgun, here we're flagging these for better awareness) and methods can be invoked with the right context too, without needing whole objects references around. On Wed, Mar 3, 2021 at 9:03 PM Augusto Moura wrote: > > that's basically the entirety of the syntax sugar proposals since > ES2015, right? > > Definitely no, but talking about the syntax additions since ES2015, they > are in one or more of the categories below: > - avoid known footguns in the language (arrow functions and lexical this, > classes and prototype, let/const and block scoping, nullish coalescing > operator, etc.) > - syntax sugars with strong community feedback AND battle proven prior art > (classes, destructuring, string templates, rest, spread and default > values, async/await, etc.) > - introducing or specifying new mechanisms that didn't exist before in > ecma (modules, classes, varargs, etc.) > > > also proxy and globalThis are *really* unrelated to this > > Proxy and globalThis (and the `with` statement for that matter), are > mechanisms of value indirection aside from the "classic" instance properties > > > while leaking objects all over down the pipe is my major concern, > something this proposal avoids, as no code will have a reference to the > entirety of the source object, they'll deal with a known property name > passed by reference, incapable of changing anything else in the source > object ... so it's rather a signal, than a convention. > > How will you prevent the passing of the object down the pipe? You mean the > reference variable being passed to another function and setting the prop > into the source object? > ```js > function foo(source) { > let { &value } = source; > value = 'foo'; > } > > function second(source) { > // You still need to pass the object forward right? > foo(source) > > // Or the proposal is something like this > let { &value } = source; > foo(value); > // and then if foo sets the value argument it should reflect in source > } > ``` > > Also the usual way of preventing the "passing the full object down" > problem is restricting the contract with other functions using a > wrapper/proxy, a well defined more specific interface or in the readonly > case just omitting the other properties > > ```ts > // Wrapper way > class Nameable { > constructor(instance) { this.#obj = instance } > get name() { return this.#obj.name } > set name(newName) { this.#obj.name = newName } > } > > function printName(nameable) { > console.log(nameable.name) > nameable.name += ' [printed]' > } > function foo(source) { > printName(new Nameable(source)) > } > foo({ name: 'foo', type: 'pojo' }) > > // Well defined contract way (using Typescript, but you could rely on duck > typing if you trust the good manners of the developers) > interface Nameable { > name: string; > } > interface Pojo extends Nameable { > type: string; > } > > function printName(nameable: Nameable) { > console.log(nameable.name) > nameable.name += ' [printed]' > // the function still can access the type field by ignoring the typing, > but at this point this is the least scary thing a developer in a app > } > function foo(source: Pojo) { > printName(source) > } > > // Omit and readonly way > function printName(nameable) { /* ... */ } > function foo(source) { > printName(pick(source, ['name'])) > } > ``` > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
es-discuss@mozilla.org
to expand further: you *could* access such reference via `arguments[0]`, but *that* won't be possible with arrow functions, as example, so that `({&reactive}, maybe) => { if (maybe) reactive = true; }` is another pattern that doesn't need the whole object around, or to be propagated, when you can pass it via `{&reactive}` to anything else, covering then the `arguments` point too. On Wed, Mar 3, 2021 at 6:44 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > > the proposal is just a debatable syntax sugar for something we already > can do > > that's basically the entirety of the syntax sugar proposals since ES2015, > right? also proxy and globalThis are *really* unrelated to this, imho, > while leaking objects all over down the pipe is my major concern, something > this proposal avoids, as no code will have a reference to the entirety of > the source object, they'll deal with a known property name passed by > reference, incapable of changing anything else in the source object ... so > it's rather a signal, than a convention. > > this means composability, different classes/prototypes passed as > arguments, and the certainty nothing can inspect, change, or deal, with the > source, which means increased security, as opposite to pass instances and > whole objects references around. > > You have a reference to a property, you don't see its source. > > > On Wed, Mar 3, 2021 at 6:19 PM Augusto Moura > wrote: > >> > ```js >> > function stuff(source, extra) { >> > const {value, method} = source; >> > >> > if (condition) >> > method.call(source); >> > >> > if (value === extra) >> > source.value = 'no more'; >> > } >> > ``` >> >> I mean, in this case you can skip destructuring altogether, having a one >> way and way only of value indirection is a Pretty Good Thing™ (even though >> we already have proxys, globalThis and other indirection shenanigans), I >> never felt annoyed of just using `source.value` or `source.method()` >> instead of `value` and `method()`, again the proposal is just a debatable >> syntax sugar for something we already can do. I wonder if we could ever do >> the reference thingy in user-land with variable level decorators, if it >> ever gets discussed again in the meetings. Would be still kinda fishy to >> propose and implement >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
es-discuss@mozilla.org
> the proposal is just a debatable syntax sugar for something we already can do that's basically the entirety of the syntax sugar proposals since ES2015, right? also proxy and globalThis are *really* unrelated to this, imho, while leaking objects all over down the pipe is my major concern, something this proposal avoids, as no code will have a reference to the entirety of the source object, they'll deal with a known property name passed by reference, incapable of changing anything else in the source object ... so it's rather a signal, than a convention. this means composability, different classes/prototypes passed as arguments, and the certainty nothing can inspect, change, or deal, with the source, which means increased security, as opposite to pass instances and whole objects references around. You have a reference to a property, you don't see its source. On Wed, Mar 3, 2021 at 6:19 PM Augusto Moura wrote: > > ```js > > function stuff(source, extra) { > > const {value, method} = source; > > > > if (condition) > > method.call(source); > > > > if (value === extra) > > source.value = 'no more'; > > } > > ``` > > I mean, in this case you can skip destructuring altogether, having a one > way and way only of value indirection is a Pretty Good Thing™ (even though > we already have proxys, globalThis and other indirection shenanigans), I > never felt annoyed of just using `source.value` or `source.method()` > instead of `value` and `method()`, again the proposal is just a debatable > syntax sugar for something we already can do. I wonder if we could ever do > the reference thingy in user-land with variable level decorators, if it > ever gets discussed again in the meetings. Would be still kinda fishy to > propose and implement > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
es-discuss@mozilla.org
The way I see it: it's just a convention/shortcut to have the destructured object around. ```js function augment({&value}, testCase) { if (/thing/.test(testCase)) value += testCase; } let any = {value: ''}; augment(any, 'thing'); ``` The magical behavior goal is to define side effects when overwriting properties ... for instance: * a destructured property, as getter, is just a value * every destructured property can be overwritten ... as these are just references Now here some wonder: ```js let any = { get value() { return 'no setter'; }, method() { console.log(this.value); } }; function stuff({&value, &method}, extra) { method(); // "no setter" // throws an error value = extra; } ``` Basically, at the engine level, is just a shortcut for having the original destructure object around, so that both `&value` and `&method` would behave exactly like `object.value = ...` or `object.method();` I personally don't know how many times I wanted this simplicity, as opposite of going through this pattern: ```js function stuff(source, extra) { const {value, method} = source; if (condition) method.call(source); if (value === extra) source.value = 'no more'; } ``` The constant change between having the value once, then eventually needing to remember the source is missing, so the function needs refactoring, or it needs binding, or it needs ... you name it, I think referencing the source object somehow, would allow a lot of refactoring, smaller code, and easier to reason about, in IDEs (special highlights for referenced variables), in developers intent (no need to grab the source repeatedly when updates are needed), and in clarity (having an explicit & in destructuring describes the intent of wanting to deal with that value as reference). My only concern here would be: what if we pass that value to another signature? Well, as long as we don't also have a way to pass such value as reference, in example, "restructuring", as in `callback({&value, other})` instead of just `callback({value, other})`, this should be a no-brainer, but maybe the two ideas should be spec'd together, and also ship together, so that you can propagate a single "*reaction point*" down the lane, without leaking the whole object across the whole lane. I hope this makes sense, but that's the idea behind. The fact C can point at pointers and force-update this but JS needs whole objects propagations everywhere, in a highly reactive situation, like the one we have these days, bugs me way too much. Regards 👋 On Wed, Mar 3, 2021 at 4:47 PM Augusto Moura wrote: > I don't know, the by reference destructuring seems a bit too much magical, > a scoped variable that sets to a property to a object just sounds like the > old `with` statement but reduced and more explicit, given is just a sugar > and currently the problem is not a great of a pain point I would be very > picky a proposal like that, any prior art in other languages? > > Also, from a grammar/vendor implementation standpoint I would imagine the > definition of a by reference variable bind would be kinda fishy, I might be > wrong though > > Em ter., 2 de mar. de 2021 às 21:03, Claudia Meadows < > cont...@isiahmeadows.com> escreveu: > >> I would like to see this happen, though I'd like to see it integrated >> with reified refs. (I know there's a proposal laying around somewhere >> drafted up by a current or former TC39 person, but I can't find it.) >> >> - >> >> Claudia Meadows >> cont...@isiahmeadows.com >> >> >> On Tue, Mar 2, 2021 at 11:05 AM Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> Another one (cit. DJ Khaled) >>> >>> has "by reference" ever been considered as "yet another JS syntax" ??? >>> >>> let object = {value: 1}; >>> let {&value} = object; >>> value = 2; >>> >>> object.value; // 2 >>> >>> allowed everywhere destructuring is possible, throwing for frozen >>> properties ... is this just meh? .. .'cause I think, specially for function >>> signatures declaration, it might make a difference, when mutability matters. >>> >>> Cheers 👋 >>> >>> P.S. for transpilers this would simply carry, repeatedly, the initial >>> reference.prop around, instead of using just prop. >>> >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > > > -- > Atenciosamente, > > Augusto Borges de Moura > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
es-discuss@mozilla.org
Another one (cit. DJ Khaled) has "by reference" ever been considered as "yet another JS syntax" ??? let object = {value: 1}; let {&value} = object; value = 2; object.value; // 2 allowed everywhere destructuring is possible, throwing for frozen properties ... is this just meh? .. .'cause I think, specially for function signatures declaration, it might make a difference, when mutability matters. Cheers 👋 P.S. for transpilers this would simply carry, repeatedly, the initial reference.prop around, instead of using just prop. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Bind operator ... for destructuring
Hello there 👋 this is going to be quick: how about using the bind operator *at least* for destructuring? ```js // today function util(ref) { if (ref.prop === 1) ref.method(2); } // tomorrow? function util({prop, ::method}) { if (prop === 1) method(2); } ``` Such shortcut would simplify a lot of extra variables declarations and/or destructuring, both in the DOM world utilities, and in general in various helpers. Thoughts? Cheers! ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: Function.prototype.bindContext
I'm not sure I'm following, but I'm not here to find solutions, I already have solutions, I'm here to propose a new `Function.prototype.bindContext` method that doesn't require any user-land discussion/prototype pollution. Thanks. On Thu, Sep 17, 2020 at 9:25 PM Adam Eisenreich wrote: > This should able to be done via two nested WakMap, > > First level would be the function and the second the context or vice > versa. This should be able to give you the same bound function while both > are avaible, but should clear itself once the reference to function/context > is lost. > > -- Původní e-mail -- > Od: Andrea Giammarchi > Komu: es-discuss@mozilla.org > Datum: 17. 9. 2020 21:03:45 > Předmět: Proposal: Function.prototype.bindContext > > I've found myself (once again) polluting the `Function.prototype` with a > lazy method that, once invoked, grants that the returned bound function is > always the same, per context. > > # Use Case > > It's still a common footgun to add events either via `context.method` or > via `context.method.bind(context)`, where the former footgan would invoke > `method` with a global context/undefined instead of the expected context, > while the latter would make it impossible to ever remove that listener > later on. > > It's also common to use methods for timers sensitive things, and it's > indeed not by accident that `console` got "self bound", or provided as > namespace, when it used to throw if `setTimeout(console.log, 100, value)` > was used, for example. > > # Proposal > > Provide a lazy `bindContext` method that grants that if a method/function > bound the same context before, it always returns the same reference. > > # Implementation / Polyfill (lazy version) > > ```js > Function.prototype.bindContext = function (context) { > const _ = new WeakMap; > this.bindContext = bindContext; > return bindContext.call(this, context); > function bindContext(context) { > if (!_.has(context)) > _.set(context, this.bind(context)); > return _.get(context); > } > }; > ``` > > # Implementation details > > As the method suggest, and differently from `bind`, `bindContext` accepts > only one argument, and it should throw with any context that is primitive > (boolean, number, string, undefined, null), like any WeakMap key would > throw as well. > > # Why not user-land / libraries / helpers > > Because standardizing a well-known/needed utility to not footgun common > patterns would make the debate regarding global prototypes pollution > irrelevant, as it's the standard that helps us out. > > In a few words, this might erase tons of common mistakes, but it also > could be simplified within some helper/library, as long as not all of them > need to include the proposed polyfill through a package or another. > > Thanks for consideration 👋 > > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Proposal: Function.prototype.bindContext
I've found myself (once again) polluting the `Function.prototype` with a lazy method that, once invoked, grants that the returned bound function is always the same, per context. # Use Case It's still a common footgun to add events either via `context.method` or via `context.method.bind(context)`, where the former footgan would invoke `method` with a global context/undefined instead of the expected context, while the latter would make it impossible to ever remove that listener later on. It's also common to use methods for timers sensitive things, and it's indeed not by accident that `console` got "self bound", or provided as namespace, when it used to throw if `setTimeout(console.log, 100, value)` was used, for example. # Proposal Provide a lazy `bindContext` method that grants that if a method/function bound the same context before, it always returns the same reference. # Implementation / Polyfill (lazy version) ```js Function.prototype.bindContext = function (context) { const _ = new WeakMap; this.bindContext = bindContext; return bindContext.call(this, context); function bindContext(context) { if (!_.has(context)) _.set(context, this.bind(context)); return _.get(context); } }; ``` # Implementation details As the method suggest, and differently from `bind`, `bindContext` accepts only one argument, and it should throw with any context that is primitive (boolean, number, string, undefined, null), like any WeakMap key would throw as well. # Why not user-land / libraries / helpers Because standardizing a well-known/needed utility to not footgun common patterns would make the debate regarding global prototypes pollution irrelevant, as it's the standard that helps us out. In a few words, this might erase tons of common mistakes, but it also could be simplified within some helper/library, as long as not all of them need to include the proposed polyfill through a package or another. Thanks for consideration 👋 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Since JSDoc seems cerebrally dead...
Sorry, new link: https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html On Mon, Aug 17, 2020 at 8:34 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > TS supports JSDocs already > > https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#supported-jsdoc > > On Mon, Aug 17, 2020 at 8:31 PM Bergi wrote: > >> Hi, >> >> > They don't want to add TS to their stack. >> >> Then what else would they want to add to their stack? Notice one doesn't >> necessarily need the TypeScript Compiler to add TypeScript- or Flow-like >> type annotations and remove them in a build step - Babel for example >> could do that just fine as well. >> Or are you asking for a jsdoc-like thing that lives in comments, where >> the code can be run without a compilation step? >> >> kind regards, >> Bergi >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Since JSDoc seems cerebrally dead...
TS supports JSDocs already https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#supported-jsdoc On Mon, Aug 17, 2020 at 8:31 PM Bergi wrote: > Hi, > > > They don't want to add TS to their stack. > > Then what else would they want to add to their stack? Notice one doesn't > necessarily need the TypeScript Compiler to add TypeScript- or Flow-like > type annotations and remove them in a build step - Babel for example > could do that just fine as well. > Or are you asking for a jsdoc-like thing that lives in comments, where > the code can be run without a compilation step? > > kind regards, > Bergi > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Why aren't interpolation values in tagged template calls saved as a cached array?
there is some fundamental misconception of the ECMAScript standard in these examples ... to start with, assuming the same `arguments` object is passed twice to two different invokes of a callback, would break down to ES3 and lower. Secondly, interpolated values you are passing around are always different, so I can't understand why would you expect an always same Array in there ... it's not the same as the template one, which is immutable, aka frozen, and it can carry any different value at any different position. Accordingly, the current standard for template literals tags function is nearly perfect, and none of these suggestions would improve anything in the wild (using template literals since 2015, I think I've consumed them all in all flavours). Regards. On Sun, Jul 26, 2020 at 8:08 PM #!/JoePea wrote: > The following doesn't work either, and obviously it probably will > never change because it is historical: > > ```js > argsArrays = [] > > function html() { > argsArrays.push(arguments) > } > > let n = 0 > let n2 = 0 > > function render() { return html`1st: ${n++}, 2nd: ${n2++}.` } > > render() > render() > > console.log(argsArrays[0] === argsArrays[1]) // false! > ``` > > So yeah, just wondering why our only option is to use `...args` and > create new arrays each time, thus the performance is not optimized > like it is with the string parts. > > #!/JoePea > > On Sun, Jul 26, 2020 at 10:49 AM #!/JoePea wrote: > > > > What I mean is, > > > > We can currently do this (try it in console): > > > > ```js > > arrays = [] > > > > function html(parts) { arrays.push(parts) } > > > > let n = 0 > > let n2 = 0 > > > > function render() { return html`1st: ${n++}, 2nd: ${n2++}.` } > > > > render() > > render() > > > > console.log(arrays[0] === arrays[1]) // true! <--- This! > > ``` > > > > But why don't specs allows us to do the following as well? (don't run > > it, it doesn't work as intended) > > > > ```js > > partsArrays = [] > > valuesArrays = [] > > > > function html(parts, values) { > > partsArrays.push(parts) > > valuesArrays.push(values) > > } > > > > let n = 0 > > let n2 = 0 > > > > function render() { return html`1st: ${n++}, 2nd: ${n2++}.` } > > > > render() > > render() > > > > console.log(partsArrays[0] === partsArrays[1]) // true! > > console.log(valuesArrays[0] === valuesArrays[1]) // This would be > > convenient too! I think? > > ``` > > > > Instead, if we want an array of the values, we have to use `arguments` > > or `...args`. For example: > > > > ```js > > // ... same ... > > function html(parts, ...values) { > > partsArrays.push(parts) > > valuesArrays.push(values) > > } > > // ... same ... > > console.log(partsArrays[0] === partsArrays[1]) // true! > > console.log(valuesArrays[0] === valuesArrays[1]) // false! New array > every time. > > ``` > > > > Seems like it would've been great to have the cached values arrays > > too. Why isn't this the case? > > > > #!/JoePea > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Are ES Modules garbage collected? If so, do they re-execute on next import?
On a second thought ... couldn't `import.meta.cache`, or something similar, be implemented in NodeJS only? On Thu, Jul 16, 2020 at 3:44 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > FWIW explicit eviction is not only fine, if you own the code that does > that, but the only way I can code cover 100% all the branches of my > libraries. The issue here is the untrusted Web, where I'd never expect any > 3rd parts library to evict a module I am using within my code ... like ... > ever. > > Accordingly, I think Allen, if it was Allen, made the right call for ESM. > > On Thu, Jul 16, 2020 at 3:23 PM Guy Bedford wrote: > >> Node.js in the CommonJS loader and dynamic loaders like SystemJS have >> supported module unloading for many years by permitting eviction from the >> loader registry. Evicting the full parent tree was the traditional >> reloading workflow in SystemJS, but live binding pushes are also permitted >> in SystemJS as well for this. >> >> I agree there are issues and invariants of course to consider from a >> theoretical perspective, but those are decisions to be made in terms of >> what invariants are valued, and I don't feel they are necessarily absolute >> constraints. These decisions should be made based on what is best for >> the JS users and engines. Not that I feel strongly this should be a >> requirement but that it should still be open to consideration. >> >> I'm not sure it was Allen's intention to ban any concept of reloading >> modules when defining the idempotency requirement for the host resolve >> function. Perhaps he could speak to that if he's around. >> >> >> On Tue, 14 Jul 2020 at 23:05, Mark S. Miller wrote: >> >>> Only a module registry as a whole may be GCed. During the lifetime of >>> any one module registry, it can only grow. No other solution is possible. >>> >>> Btw, I remember being surprised ages ago when the same issue came up for >>> the Java ClassLoader. A classLoader holds on to all the classes it ever >>> loaded. Each class holds onto its classLoader. Each instance holds on to >>> its class. During the lifetime of a classLoader or any of its classes, the >>> graph of that classLoader and its classes can only grow new classes. Not >>> until the classLoader and all of its classes are unreachable at the same >>> time can any of them be collected. This was equally unfortunate, >>> surprising, and inescapable. >>> >>> >>> >>> On Tue, Jul 14, 2020 at 10:16 PM #!/JoePea wrote: >>> >>>> How can we ensure that long-running applications (even if theoretical), >>>> that may load and unload an unlimited number of new modules over time >>>> (f.e. routes in a web page specified by 3rd parties as time >>>> progresses), not leak memory? >>>> >>>> Even if it is theoretical, I don't like the thought of something that >>>> only ever allocates memory that will never be freed. >>>> >>>> Is someone working on a solution for this? >>>> >>>> >>>> #!/JoePea >>>> >>>> On Wed, Jul 1, 2020 at 6:16 AM Mark S. Miller >>>> wrote: >>>> > >>>> > No, definitely not. The table from specifiers to module instances is >>>> indexed by specifiers. Specifiers are strings, so this table is not weak. >>>> It is not a "cache" in the sense that it is allowed to drop things. Rather >>>> it is a registry of module instances. Only a registry as a whole can be >>>> gc'ed, and which point that context is no longer around for instantiating >>>> or reinstantiating modules. >>>> > >>>> > As you suggest, if it could drop things because of GC that it would >>>> then need to regenerate, that would expose the non-determinism of gc. That >>>> would be a big deal. We carefully designed WeakMaps so that gc was >>>> non-observable. WeakMaps introduce no observable non-determinism. WeakRefs >>>> alone expose the non-determinism of gc, and are kept well quarantined from >>>> the rest of the language. >>>> > >>>> > >>>> > On Tue, Jun 30, 2020 at 5:42 PM #!/JoePea wrote: >>>> >> >>>> >> I am curious: can modules be garbage collected if the exports are not >>>> >> references by anything anymore? And if so, will the module be >>>> >> re-evaluated the next time it is imported? >>>> >>
Re: Are ES Modules garbage collected? If so, do they re-execute on next import?
FWIW explicit eviction is not only fine, if you own the code that does that, but the only way I can code cover 100% all the branches of my libraries. The issue here is the untrusted Web, where I'd never expect any 3rd parts library to evict a module I am using within my code ... like ... ever. Accordingly, I think Allen, if it was Allen, made the right call for ESM. On Thu, Jul 16, 2020 at 3:23 PM Guy Bedford wrote: > Node.js in the CommonJS loader and dynamic loaders like SystemJS have > supported module unloading for many years by permitting eviction from the > loader registry. Evicting the full parent tree was the traditional > reloading workflow in SystemJS, but live binding pushes are also permitted > in SystemJS as well for this. > > I agree there are issues and invariants of course to consider from a > theoretical perspective, but those are decisions to be made in terms of > what invariants are valued, and I don't feel they are necessarily absolute > constraints. These decisions should be made based on what is best for > the JS users and engines. Not that I feel strongly this should be a > requirement but that it should still be open to consideration. > > I'm not sure it was Allen's intention to ban any concept of reloading > modules when defining the idempotency requirement for the host resolve > function. Perhaps he could speak to that if he's around. > > > On Tue, 14 Jul 2020 at 23:05, Mark S. Miller wrote: > >> Only a module registry as a whole may be GCed. During the lifetime of any >> one module registry, it can only grow. No other solution is possible. >> >> Btw, I remember being surprised ages ago when the same issue came up for >> the Java ClassLoader. A classLoader holds on to all the classes it ever >> loaded. Each class holds onto its classLoader. Each instance holds on to >> its class. During the lifetime of a classLoader or any of its classes, the >> graph of that classLoader and its classes can only grow new classes. Not >> until the classLoader and all of its classes are unreachable at the same >> time can any of them be collected. This was equally unfortunate, >> surprising, and inescapable. >> >> >> >> On Tue, Jul 14, 2020 at 10:16 PM #!/JoePea wrote: >> >>> How can we ensure that long-running applications (even if theoretical), >>> that may load and unload an unlimited number of new modules over time >>> (f.e. routes in a web page specified by 3rd parties as time >>> progresses), not leak memory? >>> >>> Even if it is theoretical, I don't like the thought of something that >>> only ever allocates memory that will never be freed. >>> >>> Is someone working on a solution for this? >>> >>> >>> #!/JoePea >>> >>> On Wed, Jul 1, 2020 at 6:16 AM Mark S. Miller wrote: >>> > >>> > No, definitely not. The table from specifiers to module instances is >>> indexed by specifiers. Specifiers are strings, so this table is not weak. >>> It is not a "cache" in the sense that it is allowed to drop things. Rather >>> it is a registry of module instances. Only a registry as a whole can be >>> gc'ed, and which point that context is no longer around for instantiating >>> or reinstantiating modules. >>> > >>> > As you suggest, if it could drop things because of GC that it would >>> then need to regenerate, that would expose the non-determinism of gc. That >>> would be a big deal. We carefully designed WeakMaps so that gc was >>> non-observable. WeakMaps introduce no observable non-determinism. WeakRefs >>> alone expose the non-determinism of gc, and are kept well quarantined from >>> the rest of the language. >>> > >>> > >>> > On Tue, Jun 30, 2020 at 5:42 PM #!/JoePea wrote: >>> >> >>> >> I am curious: can modules be garbage collected if the exports are not >>> >> references by anything anymore? And if so, will the module be >>> >> re-evaluated the next time it is imported? >>> >> >>> >> I haven't tried an experiment to answer this yet. I'll be back to post >>> >> findings if someone doesn't post an official answer first. >>> >> >>> >> I'm thinking about code longevity. For example, if we make >>> >> long-running web-based applications with many routes and features (for >>> >> sake of example imagine a desktop environment, or a MMORPG game, with >>> >> apps or components that are loaded within the same context). Over >>> >> time, if imports are not collected, then it means we have a memory >>> >> leak. >>> >> >>> >> Imagine, for example, an infinite-universe MMORPG where you can land >>> >> on different planets where the code for features of a planet are >>> >> provided by third parties as ES Modules. I know, this might not be a >>> >> safe idea to import any code into an app, but just imagine it for sake >>> >> of example (imagine we have a continuous integration system to test >>> >> and verify code security, or something, before that code is allowed to >>> >> be consumed in the app). Imagine you play this app for many many days, >>> >> and visit many places, and you leave the app running the w
Re: Are ES Modules garbage collected? If so, do they re-execute on next import?
even if dereferenced, a dynamic import could re-reference it any time, and I would expect it to still be the same module, it'd be a surprise otherwise (cached things, same namespace checks, etc). On Wed, Jul 1, 2020 at 7:33 AM Isiah Meadows wrote: > Just to expand on that, if the module record itself is dereferenced > (like if it's evicted from the cache somehow), then yes, it should be > collected as appropriate. However, I'm not aware of any major > implementation that offers that functionality. > > - > > Isiah Meadows > cont...@isiahmeadows.com > www.isiahmeadows.com > > On Tue, Jun 30, 2020 at 6:22 PM Gus Caplan wrote: > > > > Modules in the spec are cached by specifier by modules that import them. > Modules in major implementations are additionally cached for the entire > realm by absolute URLs. I would say that for actual code (functions and > classes and whatnot) leaks aren't really a problem. Even if you import a > ton of levels, that's not that much memory. The main concern I've seen > raised is JSON modules, where once you import them the JSON object, which > can be quite large, will never be collected. Of course, there is a simple > solution to that (fetch) so it isn't a world ending problem. > > > > On Tue, Jun 30, 2020 at 7:41 PM #!/JoePea wrote: > >> > >> I am curious: can modules be garbage collected if the exports are not > >> references by anything anymore? And if so, will the module be > >> re-evaluated the next time it is imported? > >> > >> I haven't tried an experiment to answer this yet. I'll be back to post > >> findings if someone doesn't post an official answer first. > >> > >> I'm thinking about code longevity. For example, if we make > >> long-running web-based applications with many routes and features (for > >> sake of example imagine a desktop environment, or a MMORPG game, with > >> apps or components that are loaded within the same context). Over > >> time, if imports are not collected, then it means we have a memory > >> leak. > >> > >> Imagine, for example, an infinite-universe MMORPG where you can land > >> on different planets where the code for features of a planet are > >> provided by third parties as ES Modules. I know, this might not be a > >> safe idea to import any code into an app, but just imagine it for sake > >> of example (imagine we have a continuous integration system to test > >> and verify code security, or something, before that code is allowed to > >> be consumed in the app). Imagine you play this app for many many days, > >> and visit many places, and you leave the app running the whole time > >> (because farming for resources is disabled if the app is not running, > >> or something). > >> > >> I would imagine that we want unused modules (when we leave a planet, > >> for example) to be (destroyed) garbage collected so that we don't > >> waste memory. > >> > >> #!/JoePea > >> ___ > >> es-discuss mailing list > >> es-discuss@mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss > > > > ___ > > es-discuss mailing list > > es-discuss@mozilla.org > > https://mail.mozilla.org/listinfo/es-discuss > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A Function.tag proposal?
I think it doesn't matter where it lands, and I've overlooked at the already available String.raw. My idea is to have it "no matter where, or how named" as it's the functionality I am after, not the name. String.plain sounds great, but since template literals tag functions are named "template literals tag functions", I've thought String.tag would implicitly describe the intent. And then again, I don't care about the name, "we" (developers that use template literals a lot) would love it no matter how it's called ;-) On Mon, Jun 22, 2020 at 7:16 PM Bergi wrote: > Hi Andrea, > > my 5ct: Putting the static function on the `Function` object doesn't > make any sense to me. Using `String.tag` seems like much more sensible > choice. Or, how about `String.plain`, in contrast to `String.raw`? > > I can see the use case, altough I'd really prefer tooling to become more > intelligent in that regard. > > best, > Bergi > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A Function.tag proposal?
btw, in case somebody reads this issue, this is the current workaround: ```js const tag = (raw, ...values) => String.raw({raw}, ...values); ``` it's still better than my dummy tag (hopefully at least on performance), but as it's becoming more common than ever, it'd be great to have `String.tag` doing exactly that. Best Regards On Mon, Jun 22, 2020 at 2:30 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > It doesn't work. There's been a lengthy discussion here > https://github.com/mjbvz/vscode-lit-html/issues/14 and comments are not > welcome in most tools, but even GitHub fails at highlighting the string, > and no intellisense works within comments. > > The simplest request considered as "increased JS complexity" also feels a > bit of an exaggeration: there are various use cases, and I wouldn't have > proposed this if useless. > > Although, `String.tag` instead of `String.raw` seems like a welcome > compromise, actually even more semantic, so the proposal would be to add a > tag that does exactly what `String.raw` does without escaping sequences. > > As there is already an identical function that is a footgun for the > described use-case, I don't see any extra complexity in having `String.tag`. > > Best Regards. > > On Mon, Jun 22, 2020 at 2:00 PM Bruno Macabeus > wrote: > >> You could just use comments in order to provide metainformations to your >> developer tools instead of adding a new feature on language. >> >> const style = /*css*/` >> body { >> color: green; >> } >> `; >> >> const node = /*html*/` >> hello world >> `; >> >> Or an even better solution is change your highlight to firstly try to match >> a HTML, if fail try to match CSS, if fail match as a plain string. >> >> IMHO it isn't necessary to increase the complexity of JS to do that. >> >> >> On Mon, 22 Jun 2020 at 12:02, François REMY < >> francois.remy@outlook.com> wrote: >> >>> What exactly are you proposing to do differently than String.raw? >>> >>> >>> https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/string/raw >>> >>> Sent from my phone >>> -- >>> *From:* es-discuss on behalf of Andrea >>> Giammarchi >>> *Sent:* Monday, June 22, 2020 12:24:13 PM >>> *To:* es-discuss@mozilla.org >>> *Subject:* A Function.tag proposal? >>> >>> This is something somehow bothering developers and tools, sooner or >>> later, the need for a no-op template literal tag function that just returns >>> the string as is. >>> >>> The current workaround to have highlights, proper content minification, >>> etc, is the following one: >>> >>> ```js >>> >>> import css from 'dummy-tag';import html from 'dummy-tag'; >>> const style = css` body {color: green; }`; >>> const node = html` hello world`; >>> >>> ``` >>> >>> but as irrelevant as the dummy-tag code is, in size, it's a dependency, >>> and a function that can't get easily optimized, due the nature of the tag >>> signature. >>> >>> ### Proposal >>> >>> Provide a static `Function.tag` which internally flattens out any >>> template literal content. >>> >>> ```js >>> >>> const css = Function.tag; >>> const html = Function.tag; >>> >>> const style = css` body {color: green; }`; >>> const node = html` hello world`; >>> >>> ``` >>> >>> Internally it will place eventual interpolations within template chunks, >>> and return a string. >>> >>> ```js >>> Function.tag`1${2}3` === '123'; >>> ``` >>> >>> That's it. Thoughts? >>> >>> Best Regards >>> >>> >>> >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A Function.tag proposal?
It doesn't work. There's been a lengthy discussion here https://github.com/mjbvz/vscode-lit-html/issues/14 and comments are not welcome in most tools, but even GitHub fails at highlighting the string, and no intellisense works within comments. The simplest request considered as "increased JS complexity" also feels a bit of an exaggeration: there are various use cases, and I wouldn't have proposed this if useless. Although, `String.tag` instead of `String.raw` seems like a welcome compromise, actually even more semantic, so the proposal would be to add a tag that does exactly what `String.raw` does without escaping sequences. As there is already an identical function that is a footgun for the described use-case, I don't see any extra complexity in having `String.tag`. Best Regards. On Mon, Jun 22, 2020 at 2:00 PM Bruno Macabeus wrote: > You could just use comments in order to provide metainformations to your > developer tools instead of adding a new feature on language. > > const style = /*css*/` > body { > color: green; > } > `; > > const node = /*html*/` > hello world > `; > > Or an even better solution is change your highlight to firstly try to match a > HTML, if fail try to match CSS, if fail match as a plain string. > > IMHO it isn't necessary to increase the complexity of JS to do that. > > > On Mon, 22 Jun 2020 at 12:02, François REMY > wrote: > >> What exactly are you proposing to do differently than String.raw? >> >> >> https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/string/raw >> >> Sent from my phone >> -- >> *From:* es-discuss on behalf of Andrea >> Giammarchi >> *Sent:* Monday, June 22, 2020 12:24:13 PM >> *To:* es-discuss@mozilla.org >> *Subject:* A Function.tag proposal? >> >> This is something somehow bothering developers and tools, sooner or >> later, the need for a no-op template literal tag function that just returns >> the string as is. >> >> The current workaround to have highlights, proper content minification, >> etc, is the following one: >> >> ```js >> >> import css from 'dummy-tag';import html from 'dummy-tag'; >> const style = css` body {color: green; }`; >> const node = html` hello world`; >> >> ``` >> >> but as irrelevant as the dummy-tag code is, in size, it's a dependency, >> and a function that can't get easily optimized, due the nature of the tag >> signature. >> >> ### Proposal >> >> Provide a static `Function.tag` which internally flattens out any >> template literal content. >> >> ```js >> >> const css = Function.tag; >> const html = Function.tag; >> >> const style = css` body {color: green; }`; >> const node = html` hello world`; >> >> ``` >> >> Internally it will place eventual interpolations within template chunks, >> and return a string. >> >> ```js >> Function.tag`1${2}3` === '123'; >> ``` >> >> That's it. Thoughts? >> >> Best Regards >> >> >> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: A Function.tag proposal?
That is not raw. On Mon, Jun 22, 2020 at 1:02 PM François REMY wrote: > What exactly are you proposing to do differently than String.raw? > > > https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/string/raw > > Sent from my phone > -- > *From:* es-discuss on behalf of Andrea > Giammarchi > *Sent:* Monday, June 22, 2020 12:24:13 PM > *To:* es-discuss@mozilla.org > *Subject:* A Function.tag proposal? > > This is something somehow bothering developers and tools, sooner or later, > the need for a no-op template literal tag function that just returns the > string as is. > > The current workaround to have highlights, proper content minification, > etc, is the following one: > > ```js > > import css from 'dummy-tag';import html from 'dummy-tag'; > const style = css` body {color: green; }`; > const node = html` hello world`; > > ``` > > but as irrelevant as the dummy-tag code is, in size, it's a dependency, > and a function that can't get easily optimized, due the nature of the tag > signature. > > ### Proposal > > Provide a static `Function.tag` which internally flattens out any template > literal content. > > ```js > > const css = Function.tag; > const html = Function.tag; > > const style = css` body {color: green; }`; > const node = html` hello world`; > > ``` > > Internally it will place eventual interpolations within template chunks, > and return a string. > > ```js > Function.tag`1${2}3` === '123'; > ``` > > That's it. Thoughts? > > Best Regards > > > > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
A Function.tag proposal?
This is something somehow bothering developers and tools, sooner or later, the need for a no-op template literal tag function that just returns the string as is. The current workaround to have highlights, proper content minification, etc, is the following one: ```js import css from 'dummy-tag';import html from 'dummy-tag'; const style = css` body {color: green; }`; const node = html` hello world`; ``` but as irrelevant as the dummy-tag code is, in size, it's a dependency, and a function that can't get easily optimized, due the nature of the tag signature. ### Proposal Provide a static `Function.tag` which internally flattens out any template literal content. ```js const css = Function.tag; const html = Function.tag; const style = css` body {color: green; }`; const node = html` hello world`; ``` Internally it will place eventual interpolations within template chunks, and return a string. ```js Function.tag`1${2}3` === '123'; ``` That's it. Thoughts? Best Regards ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Any chance for an `Object.assignProperties` ?
Anyway, if anyone is interested, I've published the `assign-properties` module [1] [1] https://github.com/WebReflection/assign-properties#readme On Thu, Feb 13, 2020 at 7:51 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > The fact `assign` doesn't copy descriptors and has potential side-effects > is documented extensively though, meaning there is room for improvement, or > simply a missing native way to do that, like it was for > `getOwnPropertyDescriptors`, that following your logic should've never > landed. > > But I guess I'd go with the usual "yet another micro library" approach > instead, so that at least I won't have to deal with assign shenanigans when > I mean to copy accessors too. > > On Thu, Feb 13, 2020 at 7:33 PM Jordan Harband wrote: > >> It seems like it’s the exact implementation you want, just for 1 object >> instead of N. >> >> Object.assign was added because versions of it were all over the web, >> used very frequently. How frequent is the pattern where people want to copy >> descriptors, such that it would deserve reification in the language? >> >> On Thu, Feb 13, 2020 at 10:23 AM Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> That has nothing to do with this, right? >>> >>> ```js >>> const {assign, defineProperties, getOwnPropertyDescriptors} = Object; >>> const assignProperties = (base, ...mixins) => defineProperties( >>> base, >>> mixins.reduce( >>> (descriptors, mixin) => assign( >>> descriptors, >>> getOwnPropertyDescriptors(mixin) >>> ), >>> {} >>> ) >>> ); >>> ``` >>> >>> On Thu, Feb 13, 2020 at 6:51 PM Jordan Harband wrote: >>> >>>> `Object.defineProperties(target, >>>> Object.getOwnPropertyDescriptors(source))`? >>>> >>>> On Thu, Feb 13, 2020 at 2:24 AM Andrea Giammarchi < >>>> andrea.giammar...@gmail.com> wrote: >>>> >>>>> Both `Object.assign` and `{...extend}` suffer a tiny gotcha: >>>>> properties are never assigned, neither retrieved, as accessors, with >>>>> side-effects too. >>>>> >>>>> Example: >>>>> ```js >>>>> const Counter = { >>>>> _count: 0, >>>>> get count() { >>>>> return this._count++; >>>>> } >>>>> }; >>>>> >>>>> const incr1 = Object.assign({}, Counter); >>>>> const incr2 = {...Counter}; >>>>> >>>>> console.log( >>>>> incr1.count,// 0 >>>>> incr2.count,// 1 >>>>> Counter._count // 2 >>>>> ); >>>>> >>>>> // functionality also compromised >>>>> console.log(incr1.count === incr1.count); >>>>> ``` >>>>> >>>>> Not only most of the time this is unexpected, but there's literally no >>>>> way to pass along accessors with a similar `Object.assign` ease, even if >>>>> that's what most developers would expect (at least up to the first time >>>>> they encounter above issue). >>>>> >>>>> How about we introduce `Object.assignProperties` instead? >>>>> >>>>> A polyfill example: >>>>> >>>>> ```js >>>>> const {assign, defineProperties, getOwnPropertyDescriptors} = Object; >>>>> const assignProperties = (base, ...mixins) => defineProperties( >>>>> base, >>>>> mixins.reduce( >>>>> (descriptors, mixin) => assign( >>>>> descriptors, >>>>> getOwnPropertyDescriptors(mixin) >>>>> ), >>>>> {} >>>>> ) >>>>> ); >>>>> ``` >>>>> >>>>> We can now use objects and mixins without side-effecting sources used >>>>> to extend, and preserving accessors in the process. >>>>> >>>>> ```js >>>>> const Counter = { >>>>> _count: 0, >>>>> get count() { >>>>> return this._count++; >>>>> } >>>>> }; >>>>> >>>>> const incr1 = Object.assignProperties({}, Counter); >>>>> const incr2 = Object.assignProperties({}, Counter); >>>>> >>>>> console.log( >>>>> incr1.count,// 0 >>>>> incr2.count,// 0 >>>>> Counter._count // 0 >>>>> ); >>>>> >>>>> // always false: preserved functionality >>>>> console.log(incr1.count === incr1.count); >>>>> ``` >>>>> >>>>> Thoughts ? >>>>> ___ >>>>> es-discuss mailing list >>>>> es-discuss@mozilla.org >>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>> >>>> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Any chance for an `Object.assignProperties` ?
The fact `assign` doesn't copy descriptors and has potential side-effects is documented extensively though, meaning there is room for improvement, or simply a missing native way to do that, like it was for `getOwnPropertyDescriptors`, that following your logic should've never landed. But I guess I'd go with the usual "yet another micro library" approach instead, so that at least I won't have to deal with assign shenanigans when I mean to copy accessors too. On Thu, Feb 13, 2020 at 7:33 PM Jordan Harband wrote: > It seems like it’s the exact implementation you want, just for 1 object > instead of N. > > Object.assign was added because versions of it were all over the web, used > very frequently. How frequent is the pattern where people want to copy > descriptors, such that it would deserve reification in the language? > > On Thu, Feb 13, 2020 at 10:23 AM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> That has nothing to do with this, right? >> >> ```js >> const {assign, defineProperties, getOwnPropertyDescriptors} = Object; >> const assignProperties = (base, ...mixins) => defineProperties( >> base, >> mixins.reduce( >> (descriptors, mixin) => assign( >> descriptors, >> getOwnPropertyDescriptors(mixin) >> ), >> {} >> ) >> ); >> ``` >> >> On Thu, Feb 13, 2020 at 6:51 PM Jordan Harband wrote: >> >>> `Object.defineProperties(target, >>> Object.getOwnPropertyDescriptors(source))`? >>> >>> On Thu, Feb 13, 2020 at 2:24 AM Andrea Giammarchi < >>> andrea.giammar...@gmail.com> wrote: >>> >>>> Both `Object.assign` and `{...extend}` suffer a tiny gotcha: properties >>>> are never assigned, neither retrieved, as accessors, with side-effects too. >>>> >>>> Example: >>>> ```js >>>> const Counter = { >>>> _count: 0, >>>> get count() { >>>> return this._count++; >>>> } >>>> }; >>>> >>>> const incr1 = Object.assign({}, Counter); >>>> const incr2 = {...Counter}; >>>> >>>> console.log( >>>> incr1.count,// 0 >>>> incr2.count,// 1 >>>> Counter._count // 2 >>>> ); >>>> >>>> // functionality also compromised >>>> console.log(incr1.count === incr1.count); >>>> ``` >>>> >>>> Not only most of the time this is unexpected, but there's literally no >>>> way to pass along accessors with a similar `Object.assign` ease, even if >>>> that's what most developers would expect (at least up to the first time >>>> they encounter above issue). >>>> >>>> How about we introduce `Object.assignProperties` instead? >>>> >>>> A polyfill example: >>>> >>>> ```js >>>> const {assign, defineProperties, getOwnPropertyDescriptors} = Object; >>>> const assignProperties = (base, ...mixins) => defineProperties( >>>> base, >>>> mixins.reduce( >>>> (descriptors, mixin) => assign( >>>> descriptors, >>>> getOwnPropertyDescriptors(mixin) >>>> ), >>>> {} >>>> ) >>>> ); >>>> ``` >>>> >>>> We can now use objects and mixins without side-effecting sources used >>>> to extend, and preserving accessors in the process. >>>> >>>> ```js >>>> const Counter = { >>>> _count: 0, >>>> get count() { >>>> return this._count++; >>>> } >>>> }; >>>> >>>> const incr1 = Object.assignProperties({}, Counter); >>>> const incr2 = Object.assignProperties({}, Counter); >>>> >>>> console.log( >>>> incr1.count,// 0 >>>> incr2.count,// 0 >>>> Counter._count // 0 >>>> ); >>>> >>>> // always false: preserved functionality >>>> console.log(incr1.count === incr1.count); >>>> ``` >>>> >>>> Thoughts ? >>>> ___ >>>> es-discuss mailing list >>>> es-discuss@mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Any chance for an `Object.assignProperties` ?
That has nothing to do with this, right? ```js const {assign, defineProperties, getOwnPropertyDescriptors} = Object; const assignProperties = (base, ...mixins) => defineProperties( base, mixins.reduce( (descriptors, mixin) => assign( descriptors, getOwnPropertyDescriptors(mixin) ), {} ) ); ``` On Thu, Feb 13, 2020 at 6:51 PM Jordan Harband wrote: > `Object.defineProperties(target, > Object.getOwnPropertyDescriptors(source))`? > > On Thu, Feb 13, 2020 at 2:24 AM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> Both `Object.assign` and `{...extend}` suffer a tiny gotcha: properties >> are never assigned, neither retrieved, as accessors, with side-effects too. >> >> Example: >> ```js >> const Counter = { >> _count: 0, >> get count() { >> return this._count++; >> } >> }; >> >> const incr1 = Object.assign({}, Counter); >> const incr2 = {...Counter}; >> >> console.log( >> incr1.count,// 0 >> incr2.count,// 1 >> Counter._count // 2 >> ); >> >> // functionality also compromised >> console.log(incr1.count === incr1.count); >> ``` >> >> Not only most of the time this is unexpected, but there's literally no >> way to pass along accessors with a similar `Object.assign` ease, even if >> that's what most developers would expect (at least up to the first time >> they encounter above issue). >> >> How about we introduce `Object.assignProperties` instead? >> >> A polyfill example: >> >> ```js >> const {assign, defineProperties, getOwnPropertyDescriptors} = Object; >> const assignProperties = (base, ...mixins) => defineProperties( >> base, >> mixins.reduce( >> (descriptors, mixin) => assign( >> descriptors, >> getOwnPropertyDescriptors(mixin) >> ), >> {} >> ) >> ); >> ``` >> >> We can now use objects and mixins without side-effecting sources used to >> extend, and preserving accessors in the process. >> >> ```js >> const Counter = { >> _count: 0, >> get count() { >> return this._count++; >> } >> }; >> >> const incr1 = Object.assignProperties({}, Counter); >> const incr2 = Object.assignProperties({}, Counter); >> >> console.log( >> incr1.count,// 0 >> incr2.count,// 0 >> Counter._count // 0 >> ); >> >> // always false: preserved functionality >> console.log(incr1.count === incr1.count); >> ``` >> >> Thoughts ? >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Any chance for an `Object.assignProperties` ?
Both `Object.assign` and `{...extend}` suffer a tiny gotcha: properties are never assigned, neither retrieved, as accessors, with side-effects too. Example: ```js const Counter = { _count: 0, get count() { return this._count++; } }; const incr1 = Object.assign({}, Counter); const incr2 = {...Counter}; console.log( incr1.count,// 0 incr2.count,// 1 Counter._count // 2 ); // functionality also compromised console.log(incr1.count === incr1.count); ``` Not only most of the time this is unexpected, but there's literally no way to pass along accessors with a similar `Object.assign` ease, even if that's what most developers would expect (at least up to the first time they encounter above issue). How about we introduce `Object.assignProperties` instead? A polyfill example: ```js const {assign, defineProperties, getOwnPropertyDescriptors} = Object; const assignProperties = (base, ...mixins) => defineProperties( base, mixins.reduce( (descriptors, mixin) => assign( descriptors, getOwnPropertyDescriptors(mixin) ), {} ) ); ``` We can now use objects and mixins without side-effecting sources used to extend, and preserving accessors in the process. ```js const Counter = { _count: 0, get count() { return this._count++; } }; const incr1 = Object.assignProperties({}, Counter); const incr2 = Object.assignProperties({}, Counter); console.log( incr1.count,// 0 incr2.count,// 0 Counter._count // 0 ); // always false: preserved functionality console.log(incr1.count === incr1.count); ``` Thoughts ? ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Yet another attempt at typed JS data
That indeed worked: ``` V8 version 8.2.34 d8> %DebugPrint(Array.from(Array(2), (_, i) => i)); DebugPrint: 0x1c67080c5ddd: [JSArray] - map: 0x1c67082817f1 [FastProperties] - prototype: 0x1c6708248f7d - elements: 0x1c67080c5ded [PACKED_SMI_ELEMENTS] - length: 2 - properties: 0x1c67080406e9 { #length: 0x1c67081c0165 (const accessor descriptor) } - elements: 0x1c67080c5ded { 0: 0 1: 1 2-3: 0x1c6708040385 } 0x1c67082817f1: [Map] - type: JS_ARRAY_TYPE - instance size: 16 - inobject properties: 0 - elements kind: PACKED_SMI_ELEMENTS - unused property fields: 0 - enum length: invalid - back pointer: 0x1c670804030d - prototype_validity cell: 0x1c67081c0451 - instance descriptors #1: 0x1c6708249605 - transitions #1: 0x1c6708249621 Transition array #1: 0x1c6708042e91 : (transition to HOLEY_SMI_ELEMENTS) -> 0x1c6708281869 - prototype: 0x1c6708248f7d - constructor: 0x1c6708248e51 - dependent code: 0x1c67080401ed - construction counter: 0 [0, 1] ``` > It could maybe be a conceivable argument for introducing `Array.createAsNonSparse(2)`. My proposal basically boils down, if we don't like the `TypedArray` concept, to this: ```js Array.createAsNonSparse( length, // pre-defined length of the Array optionalValueOrCallback // values per each entry ); Array.createAsNonSparse(3, 0); // [0, 0, 0] non sparsed Array.createAsNonSparse(3, i => i * i); // [0, 1, 4] non sparsed ``` Would this makes more sense? It'd be super handy in many cases, as many developers don't even know what is a holey/sparsed Array, neither how to *not* create one. If the second argument is too ambiguous, I wouldn't mind having it as function all the time: ```js Array.createAsNonSparse(3); // [undefined, undefined, undefined] non sparsed Array.createAsNonSparse(3, () => 0); // [0, 0, 0] non sparsed Array.createAsNonSparse(3, i => i * i); // [0, 1, 4] non sparsed ``` Thanks. On Wed, Feb 12, 2020 at 12:51 PM Claude Pache wrote: > At some point in the algorithm of [Array.from], the newly-created array > will indeed be created as sparse (at steps 9/10), but this is usually not > observable (that is, unless you are creating an instance of a subclass of > Array with very unusual behaviour) as far as the spec is concerned > (optimisation is not part of the spec). > > If it is important for you to circumvent the v8 limitation in its > optimisation process, you should be able to write `Array.from(Array(2), _ > => undefined)`: the array will be created as non-sparse at steps 5.a/b. > > In any case, this optimisation detail is by very far not a satisfactory > argument for introducing the heavy feature you proposed. It could maybe be > a conceivable argument for introducing `Array.createAsNonSparse(2)`. > > [Array.from]: https://tc39.es/ecma262/#sec-array.from > > —Claude > > > Le 12 févr. 2020 à 10:23, Andrea Giammarchi > a écrit : > > Which part of `HOLEY_SMI_ELEMENTS` makes you think so? > > V8 version 8.2.34 > d8> %DebugPrint(Array.from({length: 2}, (_, i) => i)) > DebugPrint: 0x5ab080c5ded: [JSArray] > - map: 0x05ab08281869 [FastProperties] > - prototype: 0x05ab08248f7d > - elements: 0x05ab080c5dfd [HOLEY_SMI_ELEMENTS] > - length: 2 > - properties: 0x05ab080406e9 { > #length: 0x05ab081c0165 (const accessor descriptor) > } > - elements: 0x05ab080c5dfd { >0: 0 >1: 1 > } > 0x5ab08281869: [Map] > - type: JS_ARRAY_TYPE > - instance size: 16 > - inobject properties: 0 > - elements kind: HOLEY_SMI_ELEMENTS > - unused property fields: 0 > - enum length: invalid > - back pointer: 0x05ab082817f1 > - prototype_validity cell: 0x05ab081c0451 > - instance descriptors #1: 0x05ab08249605 > - transitions #1: 0x05ab08249639 Transition array #1: > 0x05ab08042e91 : (transition to > PACKED_DOUBLE_ELEMENTS) -> 0x05ab08281891 > > - prototype: 0x05ab08248f7d > - constructor: 0x05ab08248e51 > - dependent code: 0x05ab080401ed (WEAK_FIXED_ARRAY_TYPE)> > - construction counter: 0 > > [0, 1] > > On Wed, Feb 12, 2020 at 7:01 AM Jordan Harband wrote: > >> No, `Array.from` never produces a holey array whatsoever; only ever a >> dense array. >> >> On Sun, Feb 9, 2020 at 11:08 PM Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> Unfortunately, `Array.from({ length: 4 }, () => whatever)` produces a >>> holey array, so that the `.repeat(...)` idea, if capable of packing >>> elements in a better way, wouldn't be so terrible, as simplification. >>> >>> Although, the intent of this proposal was to also grant "shapes" or >>> kindness of each entry, same way typed Arrays
Re: Yet another attempt at typed JS data
Which part of `HOLEY_SMI_ELEMENTS` makes you think so? V8 version 8.2.34 d8> %DebugPrint(Array.from({length: 2}, (_, i) => i)) DebugPrint: 0x5ab080c5ded: [JSArray] - map: 0x05ab08281869 [FastProperties] - prototype: 0x05ab08248f7d - elements: 0x05ab080c5dfd [HOLEY_SMI_ELEMENTS] - length: 2 - properties: 0x05ab080406e9 { #length: 0x05ab081c0165 (const accessor descriptor) } - elements: 0x05ab080c5dfd { 0: 0 1: 1 } 0x5ab08281869: [Map] - type: JS_ARRAY_TYPE - instance size: 16 - inobject properties: 0 - elements kind: HOLEY_SMI_ELEMENTS - unused property fields: 0 - enum length: invalid - back pointer: 0x05ab082817f1 - prototype_validity cell: 0x05ab081c0451 - instance descriptors #1: 0x05ab08249605 - transitions #1: 0x05ab08249639 Transition array #1: 0x05ab08042e91 : (transition to PACKED_DOUBLE_ELEMENTS) -> 0x05ab08281891 - prototype: 0x05ab08248f7d - constructor: 0x05ab08248e51 - dependent code: 0x05ab080401ed - construction counter: 0 [0, 1] On Wed, Feb 12, 2020 at 7:01 AM Jordan Harband wrote: > No, `Array.from` never produces a holey array whatsoever; only ever a > dense array. > > On Sun, Feb 9, 2020 at 11:08 PM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> Unfortunately, `Array.from({ length: 4 }, () => whatever)` produces a >> holey array, so that the `.repeat(...)` idea, if capable of packing >> elements in a better way, wouldn't be so terrible, as simplification. >> >> Although, the intent of this proposal was to also grant "shapes" or >> kindness of each entry, same way typed Arrays do, but maybe that would >> require some better primitive, as in `const Shape = >> Object.defineShape(...)` and `Object.createShape(Shape)` or similar. >> >> On Sun, Feb 9, 2020 at 10:01 PM Jordan Harband wrote: >> >>> That already exists - `Array.from({ length: 4 }, () => whatever)` - I >>> assume that the hope is to have an array where it is *impossible* for it to >>> have the wrong "kind" of data, and a userland factory function wouldn't >>> provide that. >>> >>> On Sun, Feb 9, 2020 at 10:39 AM kai zhu wrote: >>> >>>> > It's a bit of a mess to create an Array that is not holed and gets >>>> best optimizations [1], and this proposal would like to address that exact >>>> case. >>>> >>>> could the performance issue be resolved more easily with a simple >>>> static-function `Array.repeat(, )`? >>>> >>>> ```js >>>> let structuredList; >>>> structuredList = Array.repeat(4, function (ii) { >>>> return { >>>> index: 2 * ii + 1, >>>> tags: [] >>>> }); >>>> /* >>>> structuredList = [ >>>> { index: 1, tags: [] }, >>>> { index: 3, tags: [] }, >>>> { index: 5, tags: [] }, >>>> { index: 7, tags: [] } >>>> ]; >>>> */ >>>> ``` >>>> >>>> the only time i can practically enforce the shape of a >>>> "StructuredArray" is during element-insertion, >>>> and a userland insertion/creation function would be just as effective >>>> as a StructuredArray constructor. >>>> >>>> enforcing shapes during element deletions and updates are going to be >>>> hard >>>> and likely just as confusing with StructuredArray as they are with >>>> regular Array. >>>> >>>> also note that most javascript arrays need to be easily JSON-serialized >>>> for message-passing >>>> over-the-wire (commonly http) to external systems. >>>> >>>> -kai >>>> >>>> On Sat, Feb 8, 2020 at 3:46 AM Andrea Giammarchi < >>>> andrea.giammar...@gmail.com> wrote: >>>> >>>>> > having to retroactively add checks like... >>>>> >>>>> we already have typed arrays in JS so I don't think this would be any >>>>> different >>>>> >>>>> > I _think_ that moderns virtual machines already did these >>>>> optimisations despite there isn't a TypedArray like that. >>>>> >>>>> It's a bit of a mess to create an Array that is not holed and gets >>>>> best optimizations [1], and this proposal would like to address that exact >>>>> case. >>>>> >>>>> [1] https://v8.dev/blog/elements-kinds >>>>> >>>>> >>>>> >>>>> >>>>> ___ >>>>> es-discuss mailing list >>>>> es-discuss@mozilla.org >>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>> >>>> ___ >>>> es-discuss mailing list >>>> es-discuss@mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Yet another attempt at typed JS data
So ... On Tue, Feb 11, 2020 at 5:44 PM Isiah Meadows wrote: > You have proof of this? That it doesn't produce a dense array in engines? > Yes, I have d8 traces, after long discussions in twitter too, that shows there's no way to have PACKED_SMI_ELEMENTS, but also a bug in Chromium from 2017, but if you need any other proof, I can figure out which other engine has the same issue, although I am not sure all engines follow same optimizations with the "packed" vs "holey" v8 concept. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Yet another attempt at typed JS data
> Given your history I know better than to assume what you know… I've no idea what you are talking about, but this should be no venue for these kind of answers. My history in this thread explained the proposal, the intent, and linked all the facts around it, and before your pointless answer, so please keep your biases for yourself. Thank you. On Mon, Feb 10, 2020 at 10:13 PM Michael Haufe wrote: > Given your history I know better than to assume what you know… > > > > The definition of sparse in the spec (while not explicitly in its own > section) is straightforward. > > > > V8’s inability or unwillingness to perform a safe “upcast” internally to > an appropriate tag doesn’t seem to provide enough weight to introduce a new > construct. > > > > > > *From:* Andrea Giammarchi > *Sent:* Monday, February 10, 2020 2:26 PM > *To:* Michael Haufe > *Cc:* Bergi ; es-discuss@mozilla.org > *Subject:* Re: Yet another attempt at typed JS data > > > > Great, now maybe you also read how it works behind the scene, and debug > properly to understand that every array is holey, including the latter one, > to date. > > > > https://v8.dev/blog/elements-kinds > > > > Please, let's assume for a second I knew what I was talking about, when > I've said it's a mess to not have holey arrays, thanks. > > > > On Mon, Feb 10, 2020 at 9:21 PM Michael Haufe > wrote: > > Array(3) > // [empty × 3] > > Array(3).fill() > // [undefined, undefined, undefined] > > Array(3).fill('whatever') > // ["whatever", "whatever", "whatever"] > > > -Original Message- > From: es-discuss On Behalf Of Bergi > Sent: Monday, February 10, 2020 1:27 PM > To: es-discuss@mozilla.org > Subject: Re: Yet another attempt at typed JS data > > Hello! > > > Unfortunately, `Array.from({ length: 4 }, () => whatever)` produces a > > holey array > > Does it? But really, if the performance difference betweeen HOLEY and > PACKED arrays were large enough to be relevant[1], the engine programmers > would certainly already have optimised all those trivial cases where an > array is filled gradually to produce the more efficient representation. > > kind regards, > Bergi > > [1]: it probably isn't: > https://stackoverflow.com/questions/54481918/#comment95848513_54485509 > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Yet another attempt at typed JS data
Great, now maybe you also read how it works behind the scene, and debug properly to understand that every array is holey, including the latter one, to date. https://v8.dev/blog/elements-kinds Please, let's assume for a second I knew what I was talking about, when I've said it's a mess to not have holey arrays, thanks. On Mon, Feb 10, 2020 at 9:21 PM Michael Haufe wrote: > Array(3) > // [empty × 3] > > Array(3).fill() > // [undefined, undefined, undefined] > > Array(3).fill('whatever') > // ["whatever", "whatever", "whatever"] > > > -Original Message- > From: es-discuss On Behalf Of Bergi > Sent: Monday, February 10, 2020 1:27 PM > To: es-discuss@mozilla.org > Subject: Re: Yet another attempt at typed JS data > > Hello! > > > Unfortunately, `Array.from({ length: 4 }, () => whatever)` produces a > > holey array > > Does it? But really, if the performance difference betweeen HOLEY and > PACKED arrays were large enough to be relevant[1], the engine programmers > would certainly already have optimised all those trivial cases where an > array is filled gradually to produce the more efficient representation. > > kind regards, > Bergi > > [1]: it probably isn't: > https://stackoverflow.com/questions/54481918/#comment95848513_54485509 > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Yet another attempt at typed JS data
They couldn't even optimize the most obvious case of them all: https://bugs.chromium.org/p/v8/issues/detail?id=6892 And "javascript is not the best tool for the job" makes no sense when it's the most targeted transpiled language, but fair enough. And yes, I've used SQLite wasm version too ... as a matter of fact, it's going to be a great lazy-loaded thing for my next project, 'cause it's 1MB overhead, so not something to really promote in the wild, imho 😅 Regards. On Mon, Feb 10, 2020 at 8:26 PM Bergi wrote: > Hello! > > > Unfortunately, `Array.from({ length: 4 }, () => whatever)` produces a > holey > > array > > Does it? But really, if the performance difference betweeen HOLEY and > PACKED arrays were large enough to be relevant[1], the engine > programmers would certainly already have optimised all those trivial > cases where an array is filled gradually to produce the more efficient > representation. > > kind regards, > Bergi > > [1]: it probably isn't: > https://stackoverflow.com/questions/54481918/#comment95848513_54485509 > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Yet another attempt at typed JS data
Unfortunately, `Array.from({ length: 4 }, () => whatever)` produces a holey array, so that the `.repeat(...)` idea, if capable of packing elements in a better way, wouldn't be so terrible, as simplification. Although, the intent of this proposal was to also grant "shapes" or kindness of each entry, same way typed Arrays do, but maybe that would require some better primitive, as in `const Shape = Object.defineShape(...)` and `Object.createShape(Shape)` or similar. On Sun, Feb 9, 2020 at 10:01 PM Jordan Harband wrote: > That already exists - `Array.from({ length: 4 }, () => whatever)` - I > assume that the hope is to have an array where it is *impossible* for it to > have the wrong "kind" of data, and a userland factory function wouldn't > provide that. > > On Sun, Feb 9, 2020 at 10:39 AM kai zhu wrote: > >> > It's a bit of a mess to create an Array that is not holed and gets best >> optimizations [1], and this proposal would like to address that exact case. >> >> could the performance issue be resolved more easily with a simple >> static-function `Array.repeat(, )`? >> >> ```js >> let structuredList; >> structuredList = Array.repeat(4, function (ii) { >> return { >> index: 2 * ii + 1, >> tags: [] >> }); >> /* >> structuredList = [ >> { index: 1, tags: [] }, >> { index: 3, tags: [] }, >> { index: 5, tags: [] }, >> { index: 7, tags: [] } >> ]; >> */ >> ``` >> >> the only time i can practically enforce the shape of a "StructuredArray" >> is during element-insertion, >> and a userland insertion/creation function would be just as effective as >> a StructuredArray constructor. >> >> enforcing shapes during element deletions and updates are going to be hard >> and likely just as confusing with StructuredArray as they are with >> regular Array. >> >> also note that most javascript arrays need to be easily JSON-serialized >> for message-passing >> over-the-wire (commonly http) to external systems. >> >> -kai >> >> On Sat, Feb 8, 2020 at 3:46 AM Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> > having to retroactively add checks like... >>> >>> we already have typed arrays in JS so I don't think this would be any >>> different >>> >>> > I _think_ that moderns virtual machines already did these >>> optimisations despite there isn't a TypedArray like that. >>> >>> It's a bit of a mess to create an Array that is not holed and gets best >>> optimizations [1], and this proposal would like to address that exact case. >>> >>> [1] https://v8.dev/blog/elements-kinds >>> >>> >>> >>> >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Yet another attempt at typed JS data
> having to retroactively add checks like... we already have typed arrays in JS so I don't think this would be any different > I _think_ that moderns virtual machines already did these optimisations despite there isn't a TypedArray like that. It's a bit of a mess to create an Array that is not holed and gets best optimizations [1], and this proposal would like to address that exact case. [1] https://v8.dev/blog/elements-kinds ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Yet another attempt at typed JS data
Any name would do, I'm rather interested in the proposal itself, and its ergonomics/logic ;-) On Fri, Feb 7, 2020 at 10:11 PM Scott Rudiger wrote: > `StructuredArray` or `StructArray` for short? Just throwing it out there. > > On Fri, Feb 7, 2020, 1:08 PM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> well, this proposal has nothing to do with Typed Arrays, as these are all >> fixed size indeed ... scratch the TypedArray name, and use ArrayKind >> instead, any better outcome? >> >> On Fri, Feb 7, 2020 at 7:51 PM Jordan Harband wrote: >> >>> the "type" in Typed Arrays refers to the bit size in memory; being able >>> to pass an arbitrary value seems like it would require implementations to >>> calculate the precise (not just the maximum) memory size a single item >>> requires. >>> >>> On Fri, Feb 7, 2020 at 6:33 AM Andrea Giammarchi < >>> andrea.giammar...@gmail.com> wrote: >>> >>>> As more and more often devs are shifting into TS, or would like to have >>>> dynamic typed arrays without a fixed length, and as v8 and likely other >>>> engines too optimize a lot for same-kind arrays, I wonder what people here >>>> think about this `TypedArray` rough proposal: >>>> >>>> # Signature: >>>> >>>> ```js >>>> new TypedArray( >>>> type, // either a "type" to infer, or a shape, or a Class >>>> length // optional: if defined it's fixed size >>>> ); >>>> ``` >>>> >>>> >>>> ## About the `type` >>>> >>>> * if the inferred type is `object`: >>>> * if the object is `null`, throw new InvalidType >>>> * if the object is a literal, or its `__proto__` is either `null` >>>> or `Object.prototype, enforce own properties and respective types >>>> * if the object is not literal, fallback to object Class (`/./` is >>>> `RegExp`, `() => {}` is `Function`, etc) >>>> * if the inferred `type` is `function`, fallback to Class >>>> * if the inferred `type` is `Class`, ensure each entry is an instance >>>> of such class, or throw InvalidType >>>> * in every other case, make a _typed_ collection of `number`, >>>> `string`, `boolean`, or `symbol` >>>> >>>> >>>> ## About the `length` >>>> >>>> * if provided, the collection has a fixed, immutable, length, and >>>> each initial entry a default value >>>> >>>> >>>> # Use Cases: >>>> >>>> ```js >>>> const numbers = new TypedArray(0, 5); >>>> // creates [0, 0, 0, 0, 0] >>>> // numbers length is immutable >>>> // numbers accepts only typeof number >>>> // out of bound entries throw >>>> >>>> let numbers = new TypedArray(0); >>>> // numbers length is dynamic >>>> // numbers accepts only typeof number >>>> // out of bound entries throw >>>> >>>> const shapes = new TypedArray({name: '', age: 0}, 3); >>>> // creates [{name: '', age: 0}, {name: '', age: 0}, {name: '', age: 0}] >>>> // shapes length is immutable >>>> // shapes accepts only objects with `name` and `age` and respective >>>> types >>>> // out of bound entries throw >>>> >>>> let shapes = new TypedArray({lat: 0, long: 0}); >>>> // shapes length is dynamic >>>> // shapes accepts only objects with `lat` and `long` and respective >>>> types >>>> // out of bound entries throw >>>> >>>> const classes = new TypedArray(HTMLElement, 2); >>>> // creates [Object.create(HTMLElement.prototype), >>>> Object.create(HTMLElement.prototype)] >>>> // classes length is immutable >>>> // classes accepts only instances of HTMLElement >>>> // out of bound entries throw >>>> >>>> let classes = new TypedArray(HTMLElement); >>>> // classes length is dynamic >>>> // classes accepts only instances of HTMLElement >>>> // out of bound entries throw >>>> >>>> // more options >>>> let strings = new TypedArray(''); >>>> let booleans = new TypedArray(true); >>>> let functions = new TypedArray(Function); >>>> let coords = new TypedArray({lat: 0, long: 0}); >>>> ``` >>>> >>>> Thanks in advance for eventual thoughts on this 👋 >>>> ___ >>>> es-discuss mailing list >>>> es-discuss@mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Yet another attempt at typed JS data
well, this proposal has nothing to do with Typed Arrays, as these are all fixed size indeed ... scratch the TypedArray name, and use ArrayKind instead, any better outcome? On Fri, Feb 7, 2020 at 7:51 PM Jordan Harband wrote: > the "type" in Typed Arrays refers to the bit size in memory; being able to > pass an arbitrary value seems like it would require implementations to > calculate the precise (not just the maximum) memory size a single item > requires. > > On Fri, Feb 7, 2020 at 6:33 AM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> As more and more often devs are shifting into TS, or would like to have >> dynamic typed arrays without a fixed length, and as v8 and likely other >> engines too optimize a lot for same-kind arrays, I wonder what people here >> think about this `TypedArray` rough proposal: >> >> # Signature: >> >> ```js >> new TypedArray( >> type, // either a "type" to infer, or a shape, or a Class >> length // optional: if defined it's fixed size >> ); >> ``` >> >> >> ## About the `type` >> >> * if the inferred type is `object`: >> * if the object is `null`, throw new InvalidType >> * if the object is a literal, or its `__proto__` is either `null` or >> `Object.prototype, enforce own properties and respective types >> * if the object is not literal, fallback to object Class (`/./` is >> `RegExp`, `() => {}` is `Function`, etc) >> * if the inferred `type` is `function`, fallback to Class >> * if the inferred `type` is `Class`, ensure each entry is an instance >> of such class, or throw InvalidType >> * in every other case, make a _typed_ collection of `number`, `string`, >> `boolean`, or `symbol` >> >> >> ## About the `length` >> >> * if provided, the collection has a fixed, immutable, length, and each >> initial entry a default value >> >> >> # Use Cases: >> >> ```js >> const numbers = new TypedArray(0, 5); >> // creates [0, 0, 0, 0, 0] >> // numbers length is immutable >> // numbers accepts only typeof number >> // out of bound entries throw >> >> let numbers = new TypedArray(0); >> // numbers length is dynamic >> // numbers accepts only typeof number >> // out of bound entries throw >> >> const shapes = new TypedArray({name: '', age: 0}, 3); >> // creates [{name: '', age: 0}, {name: '', age: 0}, {name: '', age: 0}] >> // shapes length is immutable >> // shapes accepts only objects with `name` and `age` and respective types >> // out of bound entries throw >> >> let shapes = new TypedArray({lat: 0, long: 0}); >> // shapes length is dynamic >> // shapes accepts only objects with `lat` and `long` and respective types >> // out of bound entries throw >> >> const classes = new TypedArray(HTMLElement, 2); >> // creates [Object.create(HTMLElement.prototype), >> Object.create(HTMLElement.prototype)] >> // classes length is immutable >> // classes accepts only instances of HTMLElement >> // out of bound entries throw >> >> let classes = new TypedArray(HTMLElement); >> // classes length is dynamic >> // classes accepts only instances of HTMLElement >> // out of bound entries throw >> >> // more options >> let strings = new TypedArray(''); >> let booleans = new TypedArray(true); >> let functions = new TypedArray(Function); >> let coords = new TypedArray({lat: 0, long: 0}); >> ``` >> >> Thanks in advance for eventual thoughts on this 👋 >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Yet another attempt at typed JS data
As more and more often devs are shifting into TS, or would like to have dynamic typed arrays without a fixed length, and as v8 and likely other engines too optimize a lot for same-kind arrays, I wonder what people here think about this `TypedArray` rough proposal: # Signature: ```js new TypedArray( type, // either a "type" to infer, or a shape, or a Class length // optional: if defined it's fixed size ); ``` ## About the `type` * if the inferred type is `object`: * if the object is `null`, throw new InvalidType * if the object is a literal, or its `__proto__` is either `null` or `Object.prototype, enforce own properties and respective types * if the object is not literal, fallback to object Class (`/./` is `RegExp`, `() => {}` is `Function`, etc) * if the inferred `type` is `function`, fallback to Class * if the inferred `type` is `Class`, ensure each entry is an instance of such class, or throw InvalidType * in every other case, make a _typed_ collection of `number`, `string`, `boolean`, or `symbol` ## About the `length` * if provided, the collection has a fixed, immutable, length, and each initial entry a default value # Use Cases: ```js const numbers = new TypedArray(0, 5); // creates [0, 0, 0, 0, 0] // numbers length is immutable // numbers accepts only typeof number // out of bound entries throw let numbers = new TypedArray(0); // numbers length is dynamic // numbers accepts only typeof number // out of bound entries throw const shapes = new TypedArray({name: '', age: 0}, 3); // creates [{name: '', age: 0}, {name: '', age: 0}, {name: '', age: 0}] // shapes length is immutable // shapes accepts only objects with `name` and `age` and respective types // out of bound entries throw let shapes = new TypedArray({lat: 0, long: 0}); // shapes length is dynamic // shapes accepts only objects with `lat` and `long` and respective types // out of bound entries throw const classes = new TypedArray(HTMLElement, 2); // creates [Object.create(HTMLElement.prototype), Object.create(HTMLElement.prototype)] // classes length is immutable // classes accepts only instances of HTMLElement // out of bound entries throw let classes = new TypedArray(HTMLElement); // classes length is dynamic // classes accepts only instances of HTMLElement // out of bound entries throw // more options let strings = new TypedArray(''); let booleans = new TypedArray(true); let functions = new TypedArray(Function); let coords = new TypedArray({lat: 0, long: 0}); ``` Thanks in advance for eventual thoughts on this 👋 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Conditional await, anyone?
> You still seem to be misunderstanding what the execution order difference is about. If to stop this thread you need me to say I am confused about anything then fine, "I am confused", but if you keep changing my examples to make your point then this conversation goes nowhere, so I am officially out of this thread. Best Regards. On Mon, Oct 14, 2019 at 10:41 PM Tab Atkins Jr. wrote: > On Sat, Oct 12, 2019 at 7:19 AM Andrea Giammarchi > wrote: > > in order to work, `await` must be executed in an async scope/context > (either top level or within a closure). > > > > In such case, either somebody is awaiting the result of that `async` > execution, or the order doesn't matter. > > That's definitely not true. I gave you an explicit example where the > order differs. That example code is realistic if you're using the > async call for side-effects only (and thus don't care about the > returned promise), or if you're storing the returned promise in a > variable so you can pass it to one of the promise combinators later. > In either of these cases the order of execution between the sync and > async code can definitely matter. > > > The following two examples produce indeed the very same result: > > > > ```js > > (async () => { return 1; })().then(console.log); > > console.log(2); > > > > (async () => { return await 1; })().then(console.log); > > console.log(2); > > ``` > > In both of these cases, you're doing no additional work after the > "maybe async" point. That is the exact part that moves in execution > order between the two cases, so obviously you won't see any > difference. Here's a slightly altered version that shows off the > difference: > > ```js > (async () => { 1; console.log("async"); return 3; })().then(console.log); > console.log(2); > > (async () => { await 1; console.log("async"); return 3; > })().then(console.log); > console.log(2); > ``` > > In the first you'll log "async", "2", "3". In the second you'll log > "2", "async", "3". > > > As summary: the proposal was to help engines be faster when it's > possible, but devs are confused by the syntax, and maybeat the end there > wouldn't be as many benefits compared to the apparent confusion this > proposal would add. > > You still seem to be misunderstanding what the execution order > difference is about. Nobody's confused about the syntax; it's clear > enough. It just does bad, confusing things as you've presented it. > > As I said in earlier message, there *is* a way to eliminate the > execution-order difference (making it so the only difference would be > the number of microtasks when your function awaits *multiple* sync > values), which I thought you'd come up with at some point, but I'm > pretty sure it was just me misunderstanding what you'd said. > > ~TJ > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Conditional await, anyone?
in order to work, `await` must be executed in an async scope/context (either top level or within a closure). In such case, either somebody is awaiting the result of that `async` execution, or the order doesn't matter. The following two examples produce indeed the very same result: ```js (async () => { return 1; })().then(console.log); console.log(2); (async () => { return await 1; })().then(console.log); console.log(2); ``` Except the second one will be scheduled a micro task too far. Since nobody counts the amount of microtasks per async function execution, the result is practically the same, except the second example is always slower. Putting all together: ```js (async () => { return await 'third'; })().then(console.log); (async () => { return 'second'; })().then(console.log); console.log('first'); ``` If you `await` the return of an async function, you are consuming that microtask regardless, which is what `await?` here would like to avoid: do not create a micro task when it's not necessary. There's no footgun as the `await?` is an explicit intent from the developer, so if the developer knows what s/he's doing, can use `await?`, otherwise if the order of the microtask matters at all, can always just use `await`. As summary: the proposal was to help engines be faster when it's possible, but devs are confused by the syntax, and maybeat the end there wouldn't be as many benefits compared to the apparent confusion this proposal would add. I hope I've explained properly what was this about. Regards On Fri, Oct 11, 2019 at 10:43 PM Tab Atkins Jr. wrote: > On Fri, Oct 11, 2019 at 1:15 AM Andrea Giammarchi > wrote: > > Again, the `await?` is sugar for the following: > > > > ```js > > const value = await? callback(); > > > > // as sugar for > > let value = callback(); > > if ('then' in value) > > value = await value; > > ``` > > Okay, so that has the "you can't predict execution order any more" > problem. But that's not consistent with what you said in "otherwise > schedule a single microtask if none has been scheduled already, or > queue this result to the previous scheduled one", which implies a > different desugaring: > > ```js > let value = callback(); > if('then' in value || thisFunctionHasntAwaitedYet) > value = await value; > ``` > > *This* desugaring has a consistent execution order, and still meets > your goal of "don't add a bunch of microtask checkpoints for > synchronous values". > > Put another way, this `await?` is equivalent to `await` *if* you're > still in the "synchronously execute until you hit the first await" > phase of executing an async function; but it's equivalent to your > simpler desugaring ("await only if this is a thenable") after that. > > > but since I've stated already I have no interest anymore in this > proposal, we can also stop explaining to each others things we know already. > > I'm fine if you want to drop it, but we're not explaining things we > already know to each other. At least one of us is confused about > what's being proposed. And the altered desugaring I give up above at > least has a chance of happening; the only issue might be the > observability of how many microtasks get scheduled. If that's not a > problem, it might be possible to suggest this as an actual change to > how `await` works. > > ~TJ > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Conditional await, anyone?
Again, the `await?` is sugar for the following: ```js const value = await? callback(); // as sugar for let value = callback(); if ('then' in value) value = await value; ``` but since I've stated already I have no interest anymore in this proposal, we can also stop explaining to each others things we know already. Best Regards On Fri, Oct 11, 2019 at 1:32 AM Tab Atkins Jr. wrote: > On Wed, Oct 9, 2019 at 11:17 PM Andrea Giammarchi > wrote: > > > What's the order of the logs? > > > > Exactly the same, as the `await?` is inevitably inside an `async` > function which would grant a single microtask instead of N. > > I think you're misreading my example? Check this out: > http://software.hixie.ch/utilities/js/live-dom-viewer/saved/7271 > > ```html > > > function one() { > oneAsync(); > w("one A"); > } > async function oneAsync() { > await Promise.resolve(); > w("one B"); > } > > function two() { > twoAsync(); > w("two A"); > } > > async function twoAsync() { > // await? true; > w("two B"); > } > > one(); > two(); > > ``` > > This script logs: > > ``` > log: one A > log: two B > log: two A > log: one B > ``` > > A and B are logged in different order depends on whether there's an > `await` creating a microtask checkpoint or not. `await? true` won't > create a microtask checkpoint, so you'll get the two() behavior, > printing B then A. `await? Promise.resolve(true)` will create one, so > you'll get the one() behavior, printing A then B. > > > If `maybeAsync` returns twice non promises results, there is only one > microtask within the async `tasks` function, that would linearly collect > all non promises, so that above example could have 1, 2, max 4 microtasks, > instead of always 4 > > . > > To explain `await?` in steps: > > > > * is the awaited value a promise? schedule microtask > > * otherwise schedule a single microtask if none has been scheduled > already, or queue this result to the previous scheduled one > > > > This would grant same linear order and save time. > > Ah, your earlier posts didn't say that `await? nonPromise` *would* > schedule a microtask in some cases! That does change things. Hm, I > wonder if this is observably different from the current behavior? > > ~TJ > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Conditional await, anyone?
> What's the order of the logs? Exactly the same, as the `await?` is inevitably inside an `async` function which would grant a single microtask instead of N. Example: ```js async function tasks() { await? maybeAsync(); await? maybeAsync(); await? maybeAsync(); } tasks(); ``` If `maybeAsync` returns twice non promises results, there is only one microtask within the async `tasks` function, that would linearly collect all non promises, so that above example could have 1, 2, max 4 microtasks, instead of always 4 . To explain `await?` in steps: * is the awaited value a promise? schedule microtask * otherwise schedule a single microtask if none has been scheduled already, or queue this result to the previous scheduled one This would grant same linear order and save time. However, like others said already in the twitter thread, we all wish `await` was already working like that by default, while it seems to unconditionally create micro tasks even when it's not strictly necessary. On Wed, Oct 9, 2019 at 11:47 PM Tab Atkins Jr. wrote: > On Wed, Oct 9, 2019 at 12:08 AM Andrea Giammarchi > wrote: > > I don't know why this went in a completely unrelated direction so ... > I'll try to explain again what is `await?` about. > > Nah, we got it. Our complaint was still about the semantics. > > > ```js > > const value = await? callback(); > > > > // as sugar for > > let value = callback(); > > if ('then' in value) > > value = await value; > > ``` > > > > The order is guaranteed and linear in every case, so that nothing > actually change logically speaking, and the hint would be about > performance, 'cause engines don't apparently optimize non-promise based > cases. > > Expand that code so there's a caller: > > ```js > function one() { > two(); > console.log("one"); > } > async function two() { > await? maybeAsync(); > console.log("two"); > } > ``` > > What's the order of the logs? > > If maybeAsync() is synchronous, then one() calls two(), two() calls > maybeAsync() which returns immediately, and it continues to log "two" > before ending and returning execution to one(), which then logs "one" > and ends. > > If maybeAsync() returns a promise, then one() calls two(), two calls > maybeAsync() then freezes while it waits for the promise to resolve, > returning execution to one(). Since one() isn't awaiting the promise > returned by two(), it just immediately continues and logs "one" then > ends. At some point later in execution, the maybeAsync() promise > resolves, two() unfreezes, then it logs "two". > > So no, the order is not guaranteed. It's unpredictable and depends on > whether the function being await?'d returns a promise or not. If you > don't know what maybeAsync() returns, you won't be able to predict > your own execution flow, which is dangerous and a very likely source > of bugs. > > ~TJ > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Conditional await, anyone?
I don't know why this went in a completely unrelated direction so ... I'll try to explain again what is `await?` about. My first two examples show a relevant performance difference between the async code and the sync one. The async code though, has zero reasons to be async and so much slower. ```js (async () => { console.time('await'); const result = await (async () => [await 1, await 2, await 3])(); console.timeEnd('await'); return result; })(); ``` Why would `await 1` ever need to create a micro task, if already executed into a scheduled one via async? Or in general, why any callback that would early return a value that is not a promise should create a micro task? So the proposal was implemented in an attempt to de-sugar `await?` into the steps proposed by the dev I've interacted with: ```js const value = await? callback(); // as sugar for let value = callback(); if ('then' in value) value = await value; ``` The order is guaranteed and linear in every case, so that nothing actually change logically speaking, and the hint would be about performance, 'cause engines don't apparently optimize non-promise based cases. However, since the initial intent/proposal about performance got translated into everything else, I've instantly lost interest myself as it's evident an `await?` would causes more confusion than it solves. I am also not answering other points as not relevant for this idea/proposal. Thanks regardless for sharing your thoughts, it helped me see it would confuse developers. Best Regards On Tue, Oct 8, 2019 at 11:58 PM Dan Peddle wrote: > Have to agree, mixing sync and async code like this looks like a disaster > waiting to happen. Knowing which order your code will be executed in might > seem not so important for controlled environments where micro optimisations > are attractive, but thinking about trying to track down a bug through this > would drive me nuts. > > Imagine you have a cached value which can be retrieved synchronously - > other code which runs in order, and perhaps not directly part of this > chain, would be fine. When it’s not there, zalgo would indeed be released. > The solution to this is to use promises (as I’m sure you know) so you have > a consistent way of saying when something is ready... otherwise it’s > thenable sniffing all the way through the codebase. > > Async infers some kind of IO or deferred process, scheduling. If there’s a > dependency, then we need to express that. That it may be in some cases > available synchronously seems like something to be extremely wary of. > > > On 8. Oct 2019, at 22:25, Tab Atkins Jr. wrote: > > > > I'm not sure I understand the intended use-case here. If the author > > knows the function they're calling is async, they can use `await` > > normally. If they know it's not async, they can avoid `await` > > altogether. If they have no idea whether it's async or not, that means > > they just don't understand what the function is returning, which > > sounds like a really bad thing that they should fix? And in that > > case, as Gus says, `await?`'s semantics would do some confusing things > > to execution order, making the line after the `await?` either run > > *before* or *after* the calling code, depending on whether the await'd > > value was a promise or not. > > > > ~TJ > > ___ > > es-discuss mailing list > > es-discuss@mozilla.org > > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Conditional await, anyone?
When developers use `async` functions, they'll likely also await unconditionally any callback, even if such callback could return a non promise value, for whatever reason. Engines are great at optimizing stuff, but as of today, if we measure the performance difference between this code: ```js (async () => { console.time('await'); const result = await (async () => [await 1, await 2, await 3])(); console.timeEnd('await'); return result; })(); ``` and the following one: ```js (/* sync */ () => { console.time('sync'); const result = (() => [1, 2, 3])(); console.timeEnd('sync'); return result; })(); ``` we'll notice the latter is about 10 to 100 times faster than the asynchronous one. Sure thing, engines might infer returned values in some hot code and skip the microtask dance once it's sure some callback might return values that are not promises, but what if developers could give hints about this possibility? In a twitter exchange, one dev mentioned the following: > I often write: > let value = mightBePromise() > if (value && value.then) > value = await value > in hot code in my async functions, for precisely this reason (I too have measured the large perf difference). so ... how about accepting a question mark after `await` so that it's clear the developer knows the function might return non Promise based results, hence the code could be faster? ```js const value = await? callback(); ``` Above code is basically what's this thread/proposal about, adding a conditional `await` syntax, so that if the returned value is not thenable, there's no reason to waste a microtask on it. What are your thoughts? ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Optional chaining syntax but with the "mice" operator ?
Yes, we can all use N variables in the middle of a chain, but `any.thing().that.queries().rows` is a more common/natural pattern. Like in everything in JS, developers need to know what they are doing. Every operator can create bugs (i.e. NaN results or bad string concatenations instead of sums) so I'm not sold on developers being confused: they either understand the code they are writing, or they'll have code reviews from their peers that hopeful understand the code. If nobody understands the code, then the code should be changed (as in: nobody needs to use an operator they don't get). As summary, I see more advantages than disadvantages, but I've created a module to solve the same issue to let developers play with it and see if this might be an interesting extra. I am not planning to keep stating I don't find it confusing though, and if everyone else feels like it's confusing, I can live with it and move on without the mouse trap. Regards On Mon, Sep 9, 2019 at 12:02 PM Naveen Chawla wrote: > I wasn't comparing it to your `??` variant of the same cases, which has > the same issues - but only because that is a curious way of using `??` in > the first place. Ordinarily `??` would be used to resolve to a value *of > the same type* to allow clear unambiguous data flow through the variables. > > Rather, I'm comparing it to > > const > resultsContainer = db.get(SQL), > firstResultIfExists = rows?.[0] > ; > > This allows re-use of the "resultsContainer" (if desired) without creating > ambiguity about each variable's meaning. Otherwise if shoehorned into a > single variable and a developer accidentally makes a wrong presumption > about the "type" without performing an explicit "type check" (of some kind) > on the resulting variable, the function would just crash. I know JavaScript > already allows this via ?? as it's a dynamic language, but the pretty much encourages it. > > The "destructuring" example produces a buggy "rowsCount". It can only ever > be 0. However, another developer may be tempted to say `else if(rowsCount > > 1)` not realizing that it's undefined if there are actually any rows. This > is what I mean by confusing & bug prone results of the pattern. > > > On Mon, 9 Sep 2019 at 10:18, Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> I guess we have a different opinion about what's confusing and what's >> not. To me having a `??` with potential side-effects is more bug prone than >> the proposed mouse trap, as it's subtle, yet "promoted" by the `?.` + `??` >> pattern. >> >> On Mon, Sep 9, 2019 at 11:16 AM Naveen Chawla >> wrote: >> >>> "resultsContainerOrSingleResult" appears to be the end variable. I just >>> find this "shoehorning" to be a sacrifice in code clarity and >>> manageability. "rowCount" would be undefined if greater than 0 in the 2nd >>> example, it seems. Surely that is a confusing behaviour, if not bug prone >>> >>> On Mon, 9 Sep 2019, 09:17 Andrea Giammarchi, < >>> andrea.giammar...@gmail.com> wrote: >>> >>>> so *maybe* we'll come back... >>>> >>>> On Mon, Sep 9, 2019 at 10:04 AM Andrea Giammarchi < >>>> andrea.giammar...@gmail.com> wrote: >>>> >>>>> `require("module")>>>> initially explained. >>>>> >>>>> `db.get(SQL)>>>> know that won't fail but might not return the desired result, so that you >>>>> end up holding the top most object with all the informations, instead of >>>>> simply ending up with undefined. This works well with destructuring too. >>>>> >>>>> ```js >>>>> const {rowsCount, id, name, email} = db.get(SQL)>>>> if (rowCounts === 0) >>>>> askUserToRegister(); >>>>> else >>>>> showUserDetails(); >>>>> ``` >>>>> >>>>> As mentioned, there is a module that let you explicitly use this >>>>> operator through a callback that tries to be as safe as it can (void after >>>>> first `.trap` access + self clean on next microtask), so manye we'll come >>>>> back to this discussion once we all understand the use case and why it's >>>>> actually very useful in some circumstance. >>>>> >>>>> Regards >>>>> >>>>> >>>>> >>>>> On Sat, Sep 7, 2019 at 1:23 PM Naveen Chawla >>>>>
Re: Optional chaining syntax but with the "mice" operator ?
I guess we have a different opinion about what's confusing and what's not. To me having a `??` with potential side-effects is more bug prone than the proposed mouse trap, as it's subtle, yet "promoted" by the `?.` + `??` pattern. On Mon, Sep 9, 2019 at 11:16 AM Naveen Chawla wrote: > "resultsContainerOrSingleResult" appears to be the end variable. I just > find this "shoehorning" to be a sacrifice in code clarity and > manageability. "rowCount" would be undefined if greater than 0 in the 2nd > example, it seems. Surely that is a confusing behaviour, if not bug prone > > On Mon, 9 Sep 2019, 09:17 Andrea Giammarchi, > wrote: > >> so *maybe* we'll come back... >> >> On Mon, Sep 9, 2019 at 10:04 AM Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> `require("module")>> initially explained. >>> >>> `db.get(SQL)>> that won't fail but might not return the desired result, so that you end up >>> holding the top most object with all the informations, instead of simply >>> ending up with undefined. This works well with destructuring too. >>> >>> ```js >>> const {rowsCount, id, name, email} = db.get(SQL)>> if (rowCounts === 0) >>> askUserToRegister(); >>> else >>> showUserDetails(); >>> ``` >>> >>> As mentioned, there is a module that let you explicitly use this >>> operator through a callback that tries to be as safe as it can (void after >>> first `.trap` access + self clean on next microtask), so manye we'll come >>> back to this discussion once we all understand the use case and why it's >>> actually very useful in some circumstance. >>> >>> Regards >>> >>> >>> >>> On Sat, Sep 7, 2019 at 1:23 PM Naveen Chawla >>> wrote: >>> >>>> There has to be a better pattern than returning the "foo()" if the baz >>>> property doesn't exist. >>>> >>>> I'm curious what you would want to do with the resulting "foo()" >>>> anyway. I can imagine a flow where I want "bar", and it doesn't exist it >>>> doesn't. I cannot imagine wanting the "foo()" in place of it. There is type >>>> unpredictability in the result, so subsequent operations would normally >>>> expected to be impossible without type-branching. Hence my question to you >>>> about what you would typically want to do with the "foo()" if that was the >>>> returned result. >>>> >>>> On Sat, 7 Sep 2019 at 12:08, Andrea Giammarchi < >>>> andrea.giammar...@gmail.com> wrote: >>>> >>>>> Interesting I forgot about that, but it wouldn't cover the "trap here" >>>>> use case. >>>>> >>>>> foo().bar ?! what => what : what; >>>>> >>>>> I'd like to forward foo() here >>>>> >>>>> On Sat, Sep 7, 2019, 11:45 Michael Luder-Rosefield < >>>>> rosyatran...@gmail.com> wrote: >>>>> >>>>>> This is getting very reminiscent of my 'forwarding ternary' operator >>>>>> (or whatever I called it) I suggested a couple of years ago. I believe >>>>>> you >>>>>> were involved in the discussion, Andrea...! >>>>>> >>>>>> ``` >>>>>> const val = foo() ?! >>>>>> (x) => x.bar.baz : >>>>>> someFallbackValue; >>>>>> ``` >>>>>> >>>>>> On Sat, 7 Sep 2019, 10:17 Andrea Giammarchi, < >>>>>> andrea.giammar...@gmail.com> wrote: >>>>>> >>>>>>> To better answer, let's start dropping any direct access and put a >>>>>>> payload in the mix. >>>>>>> >>>>>>> As example, in the `foo()?.bar.baz` case, you might end up having >>>>>>> `null` or `undefined`, as result, because `foo().bar` existed, but >>>>>>> `bar.baz` didn't. >>>>>>> >>>>>>> In the `foo()?.bar?.baz` case, you might end up having `foo().bar`, >>>>>>> because `bar.baz` didn't exist. >>>>>>> >>>>>>> But what if you are not interested in the whole chain, but only in a >>>>>>> main specific point in such chain
Re: Optional chaining syntax but with the "mice" operator ?
so *maybe* we'll come back... On Mon, Sep 9, 2019 at 10:04 AM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > `require("module") initially explained. > > `db.get(SQL) that won't fail but might not return the desired result, so that you end up > holding the top most object with all the informations, instead of simply > ending up with undefined. This works well with destructuring too. > > ```js > const {rowsCount, id, name, email} = db.get(SQL) if (rowCounts === 0) > askUserToRegister(); > else > showUserDetails(); > ``` > > As mentioned, there is a module that let you explicitly use this operator > through a callback that tries to be as safe as it can (void after first > `.trap` access + self clean on next microtask), so manye we'll come back to > this discussion once we all understand the use case and why it's actually > very useful in some circumstance. > > Regards > > > > On Sat, Sep 7, 2019 at 1:23 PM Naveen Chawla > wrote: > >> There has to be a better pattern than returning the "foo()" if the baz >> property doesn't exist. >> >> I'm curious what you would want to do with the resulting "foo()" anyway. >> I can imagine a flow where I want "bar", and it doesn't exist it doesn't. I >> cannot imagine wanting the "foo()" in place of it. There is type >> unpredictability in the result, so subsequent operations would normally >> expected to be impossible without type-branching. Hence my question to you >> about what you would typically want to do with the "foo()" if that was the >> returned result. >> >> On Sat, 7 Sep 2019 at 12:08, Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> Interesting I forgot about that, but it wouldn't cover the "trap here" >>> use case. >>> >>> foo().bar ?! what => what : what; >>> >>> I'd like to forward foo() here >>> >>> On Sat, Sep 7, 2019, 11:45 Michael Luder-Rosefield < >>> rosyatran...@gmail.com> wrote: >>> >>>> This is getting very reminiscent of my 'forwarding ternary' operator >>>> (or whatever I called it) I suggested a couple of years ago. I believe you >>>> were involved in the discussion, Andrea...! >>>> >>>> ``` >>>> const val = foo() ?! >>>> (x) => x.bar.baz : >>>> someFallbackValue; >>>> ``` >>>> >>>> On Sat, 7 Sep 2019, 10:17 Andrea Giammarchi, < >>>> andrea.giammar...@gmail.com> wrote: >>>> >>>>> To better answer, let's start dropping any direct access and put a >>>>> payload in the mix. >>>>> >>>>> As example, in the `foo()?.bar.baz` case, you might end up having >>>>> `null` or `undefined`, as result, because `foo().bar` existed, but >>>>> `bar.baz` didn't. >>>>> >>>>> In the `foo()?.bar?.baz` case, you might end up having `foo().bar`, >>>>> because `bar.baz` didn't exist. >>>>> >>>>> But what if you are not interested in the whole chain, but only in a >>>>> main specific point in such chain? In that case you would have >>>>> `foo()?.bar.baz ?? foo()`, but you wouldn't know how to obtain that via >>>>> `foo()?.bar?.baz ?? foo()`, because the latest one might result into >>>>> `foo().bar`. >>>>> >>>>> Moreover, in both cases you'll end up multiplying the payload at least >>>>> * 2, while the mouse trap will work like this: >>>>> >>>>> ```js >>>>> foo()>>>> ``` >>>>> >>>>> if either `foo().bar` or `bar.baz` don't exist, the returned result is >>>>> `foo()`, and it's computed once. You don't care about `foo().bar` if >>>>> `bar.baz` is not there, 'cause you want to retrieve `foo()` whenever you >>>>> have a failure down the chain. >>>>> >>>>> Specially with DB operations, this is a very common case (abstraction >>>>> layers all have somehow different nested objects with various info) and >>>>> the >>>>> specific info you want to know is usually attached at the top level bject, >>>>> while crawling its sub properties either leads to the expected result or >>>>> you're left clueless about the result, 'cause all info
Re: Optional chaining syntax but with the "mice" operator ?
`require("module") wrote: > There has to be a better pattern than returning the "foo()" if the baz > property doesn't exist. > > I'm curious what you would want to do with the resulting "foo()" anyway. I > can imagine a flow where I want "bar", and it doesn't exist it doesn't. I > cannot imagine wanting the "foo()" in place of it. There is type > unpredictability in the result, so subsequent operations would normally > expected to be impossible without type-branching. Hence my question to you > about what you would typically want to do with the "foo()" if that was the > returned result. > > On Sat, 7 Sep 2019 at 12:08, Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> Interesting I forgot about that, but it wouldn't cover the "trap here" >> use case. >> >> foo().bar ?! what => what : what; >> >> I'd like to forward foo() here >> >> On Sat, Sep 7, 2019, 11:45 Michael Luder-Rosefield < >> rosyatran...@gmail.com> wrote: >> >>> This is getting very reminiscent of my 'forwarding ternary' operator (or >>> whatever I called it) I suggested a couple of years ago. I believe you were >>> involved in the discussion, Andrea...! >>> >>> ``` >>> const val = foo() ?! >>> (x) => x.bar.baz : >>> someFallbackValue; >>> ``` >>> >>> On Sat, 7 Sep 2019, 10:17 Andrea Giammarchi, < >>> andrea.giammar...@gmail.com> wrote: >>> >>>> To better answer, let's start dropping any direct access and put a >>>> payload in the mix. >>>> >>>> As example, in the `foo()?.bar.baz` case, you might end up having >>>> `null` or `undefined`, as result, because `foo().bar` existed, but >>>> `bar.baz` didn't. >>>> >>>> In the `foo()?.bar?.baz` case, you might end up having `foo().bar`, >>>> because `bar.baz` didn't exist. >>>> >>>> But what if you are not interested in the whole chain, but only in a >>>> main specific point in such chain? In that case you would have >>>> `foo()?.bar.baz ?? foo()`, but you wouldn't know how to obtain that via >>>> `foo()?.bar?.baz ?? foo()`, because the latest one might result into >>>> `foo().bar`. >>>> >>>> Moreover, in both cases you'll end up multiplying the payload at least >>>> * 2, while the mouse trap will work like this: >>>> >>>> ```js >>>> foo()>>> ``` >>>> >>>> if either `foo().bar` or `bar.baz` don't exist, the returned result is >>>> `foo()`, and it's computed once. You don't care about `foo().bar` if >>>> `bar.baz` is not there, 'cause you want to retrieve `foo()` whenever you >>>> have a failure down the chain. >>>> >>>> Specially with DB operations, this is a very common case (abstraction >>>> layers all have somehow different nested objects with various info) and the >>>> specific info you want to know is usually attached at the top level bject, >>>> while crawling its sub properties either leads to the expected result or >>>> you're left clueless about the result, 'cause all info got lost in the >>>> chain. >>>> >>>> The `foo()>>> `foo().bar` existed, there's no way to expect `foo()` as result, and if >>>> it's `bar` that you're after you can write instead `foo()?.bar>>> that if `baz` is not there, `bar` it is. >>>> >>>> This short-circuit the need for `??` in most cases, 'cause you already >>>> point at the desired result in the chain in case the result would be `null` >>>> or `undefined`. >>>> >>>> However, `??` itself doesn't provide any ability to reach any point in >>>> the previous chain that failed, so that once again, you find yourself >>>> crawling such chain as fallback, resulting potentially in multiple chains >>>> and repeated payloads. >>>> >>>> ```js >>>> // nested chains >>>> foo()?.bar.baz?.biz ?? foo()?.bar.baz ?? foo()?.bar; >>>> >>>> // mouse trap >>>> foo()?.bar>>> ``` >>>> >>>> Above example would prefer `foo().bar` if it exists, and if either >>>> `bar.baz` or `bar.baz.biz` returned `null` or `undefined`. >>>> >>>> I hope this
Re: Optional chaining syntax but with the "mice" operator ?
Interesting I forgot about that, but it wouldn't cover the "trap here" use case. foo().bar ?! what => what : what; I'd like to forward foo() here On Sat, Sep 7, 2019, 11:45 Michael Luder-Rosefield wrote: > This is getting very reminiscent of my 'forwarding ternary' operator (or > whatever I called it) I suggested a couple of years ago. I believe you were > involved in the discussion, Andrea...! > > ``` > const val = foo() ?! > (x) => x.bar.baz : > someFallbackValue; > ``` > > On Sat, 7 Sep 2019, 10:17 Andrea Giammarchi, > wrote: > >> To better answer, let's start dropping any direct access and put a >> payload in the mix. >> >> As example, in the `foo()?.bar.baz` case, you might end up having `null` >> or `undefined`, as result, because `foo().bar` existed, but `bar.baz` >> didn't. >> >> In the `foo()?.bar?.baz` case, you might end up having `foo().bar`, >> because `bar.baz` didn't exist. >> >> But what if you are not interested in the whole chain, but only in a main >> specific point in such chain? In that case you would have `foo()?.bar.baz >> ?? foo()`, but you wouldn't know how to obtain that via `foo()?.bar?.baz ?? >> foo()`, because the latest one might result into `foo().bar`. >> >> Moreover, in both cases you'll end up multiplying the payload at least * >> 2, while the mouse trap will work like this: >> >> ```js >> foo()> ``` >> >> if either `foo().bar` or `bar.baz` don't exist, the returned result is >> `foo()`, and it's computed once. You don't care about `foo().bar` if >> `bar.baz` is not there, 'cause you want to retrieve `foo()` whenever you >> have a failure down the chain. >> >> Specially with DB operations, this is a very common case (abstraction >> layers all have somehow different nested objects with various info) and the >> specific info you want to know is usually attached at the top level bject, >> while crawling its sub properties either leads to the expected result or >> you're left clueless about the result, 'cause all info got lost in the >> chain. >> >> The `foo()> `foo().bar` existed, there's no way to expect `foo()` as result, and if >> it's `bar` that you're after you can write instead `foo()?.bar> that if `baz` is not there, `bar` it is. >> >> This short-circuit the need for `??` in most cases, 'cause you already >> point at the desired result in the chain in case the result would be `null` >> or `undefined`. >> >> However, `??` itself doesn't provide any ability to reach any point in >> the previous chain that failed, so that once again, you find yourself >> crawling such chain as fallback, resulting potentially in multiple chains >> and repeated payloads. >> >> ```js >> // nested chains >> foo()?.bar.baz?.biz ?? foo()?.bar.baz ?? foo()?.bar; >> >> // mouse trap >> foo()?.bar> ``` >> >> Above example would prefer `foo().bar` if it exists, and if either >> `bar.baz` or `bar.baz.biz` returned `null` or `undefined`. >> >> I hope this clarifies further the intent, or the simplification, that >> such operator offers: it's a complementary hint for any optional chain, it >> doesn't have to be used, but when it does, it's visually semantic in its >> intent (at least to my eyes). >> >> Regards >> >> >> >> >> On Fri, Sep 6, 2019 at 11:20 PM Tab Atkins Jr. >> wrote: >> >>> On Fri, Sep 6, 2019 at 8:04 AM Andrea Giammarchi >>> wrote: >>> > Indeed I'm not super convinced myself about the "branching issue" >>> 'cause `const result = this?.is?.branching?.already` and all I am proposing >>> is to hint the syntax where to stop in case something else fails down the >>> line, as in `const result = this.?.is>> other part is not reached, there is a certain point to keep going (which >>> is, example, checking that `result !== this`) >>> >>> Important distinction there is that ?. only "branches" between the >>> intended type and undefined, not between two arbitrary types. The >>> cognitive load between those two is significantly different. >>> >>> In particular, you can't *do* anything with undefined, so >>> `foo?.bar.baz` has pretty unambiguous semantics - you don't think you >>> might be accessing the .baz property of undefined, because that >>> clearly doesn't exist. >>> >>> That's not the case with mouse, where it's not clear, at least to me, >>> whether `foo>> `foo.bar.baz ? foo.bar.baz : foo` or even `foo.bar ? foo.bar.baz : >>> foo`. All three seem at least somewhat reasonable, and definitely >>> *believable* as an interpretation! >>> >>> ~TJ >>> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Optional chaining syntax but with the "mice" operator ?
To better answer, let's start dropping any direct access and put a payload in the mix. As example, in the `foo()?.bar.baz` case, you might end up having `null` or `undefined`, as result, because `foo().bar` existed, but `bar.baz` didn't. In the `foo()?.bar?.baz` case, you might end up having `foo().bar`, because `bar.baz` didn't exist. But what if you are not interested in the whole chain, but only in a main specific point in such chain? In that case you would have `foo()?.bar.baz ?? foo()`, but you wouldn't know how to obtain that via `foo()?.bar?.baz ?? foo()`, because the latest one might result into `foo().bar`. Moreover, in both cases you'll end up multiplying the payload at least * 2, while the mouse trap will work like this: ```js foo() wrote: > On Fri, Sep 6, 2019 at 8:04 AM Andrea Giammarchi > wrote: > > Indeed I'm not super convinced myself about the "branching issue" 'cause > `const result = this?.is?.branching?.already` and all I am proposing is to > hint the syntax where to stop in case something else fails down the line, > as in `const result = this.?.is part is not reached, there is a certain point to keep going (which is, > example, checking that `result !== this`) > > Important distinction there is that ?. only "branches" between the > intended type and undefined, not between two arbitrary types. The > cognitive load between those two is significantly different. > > In particular, you can't *do* anything with undefined, so > `foo?.bar.baz` has pretty unambiguous semantics - you don't think you > might be accessing the .baz property of undefined, because that > clearly doesn't exist. > > That's not the case with mouse, where it's not clear, at least to me, > whether `foo `foo.bar.baz ? foo.bar.baz : foo` or even `foo.bar ? foo.bar.baz : > foo`. All three seem at least somewhat reasonable, and definitely > *believable* as an interpretation! > > ~TJ > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Optional chaining syntax but with the "mice" operator ?
It's On Fri, Sep 6, 2019, 20:14 Jordan Harband wrote: > Syntactically marking, in a chain, what you'd like the final value of the > chain to be, seems interesting - forcing optionality into it seems > unnecessary, though, if such a syntactic marker could be attached to all > forms of property access. > > Something like: `a.b>.c.d` or `a?.b>?.c?.d` or `a>[b][c][d]`. > > (Obviously, the `>` won't work with bracket, and any syntax for normal > properties that only applies to dot and not also bracket would somewhat be > a nonstarter; but the specific syntax can be bikeshedded separately) > > On Fri, Sep 6, 2019 at 8:04 AM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> Indeed I'm not super convinced myself about the "branching issue" 'cause >> `const result = this?.is?.branching?.already` and all I am proposing is to >> hint the syntax where to stop in case something else fails down the line, >> as in `const result = this.?.is> part is not reached, there is a certain point to keep going (which is, >> example, checking that `result !== this`) >> >> On Fri, Sep 6, 2019 at 4:17 PM Naveen Chawla >> wrote: >> >>> Typically, "dot" expressions navigate through values of different types, >>> making "type branching" the inevitable next step in those cases (unless you >>> introduce a common method for further processing for each of those types). >>> So I'm not sure how ultimately that would be avoided. >>> >>> On Fri, 6 Sep 2019 at 14:15, Claude Pache >>> wrote: >>> >>>> >>>> >>>> Le 6 sept. 2019 à 14:35, Felipe Nascimento de Moura < >>>> felipenmo...@gmail.com> a écrit : >>>> >>>> Doesn't that bring risks to breaking the web? >>>> >>>> You seen, many, MANY servers running php have the "shot-tags" feature >>>> enabled, in which pages with will be interpreted. >>>> In this case, any html page with embedded scripts using this operator, >>>> or event .js files when the server is configured to also run php in them, >>>> will break. >>>> >>>> Or am I missing something here? >>>> >>>> [ ]s >>>> >>>> >>>> Any future PHP file that incorporate that syntax will almost surely >>>> refuse to compile on servers that has short-tags enabled, making the >>>> problem evident before it produces something useful on the web. This may be >>>> an issue, but this is not what “breaking the web” is intended to mean. >>>> Existing, untouched content will not break. Carelessly updated content >>>> might break, but that’s not fundamentally different from any other careless >>>> update. >>>> >>>> (If anything else, it may convince people that having different >>>> configuration settings w.r.t. short-tags in development environment and in >>>> production environment, is a very bad idea...) >>>> >>>> —Claude >>>> ___ >>>> es-discuss mailing list >>>> es-discuss@mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Optional chaining syntax but with the "mice" operator ?
Indeed I'm not super convinced myself about the "branching issue" 'cause `const result = this?.is?.branching?.already` and all I am proposing is to hint the syntax where to stop in case something else fails down the line, as in `const result = this.?.is wrote: > Typically, "dot" expressions navigate through values of different types, > making "type branching" the inevitable next step in those cases (unless you > introduce a common method for further processing for each of those types). > So I'm not sure how ultimately that would be avoided. > > On Fri, 6 Sep 2019 at 14:15, Claude Pache wrote: > >> >> >> Le 6 sept. 2019 à 14:35, Felipe Nascimento de Moura < >> felipenmo...@gmail.com> a écrit : >> >> Doesn't that bring risks to breaking the web? >> >> You seen, many, MANY servers running php have the "shot-tags" feature >> enabled, in which pages with will be interpreted. >> In this case, any html page with embedded scripts using this operator, or >> event .js files when the server is configured to also run php in them, will >> break. >> >> Or am I missing something here? >> >> [ ]s >> >> >> Any future PHP file that incorporate that syntax will almost surely >> refuse to compile on servers that has short-tags enabled, making the >> problem evident before it produces something useful on the web. This may be >> an issue, but this is not what “breaking the web” is intended to mean. >> Existing, untouched content will not break. Carelessly updated content >> might break, but that’s not fundamentally different from any other careless >> update. >> >> (If anything else, it may convince people that having different >> configuration settings w.r.t. short-tags in development environment and in >> production environment, is a very bad idea...) >> >> —Claude >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Optional chaining syntax but with the "mice" operator ?
You keep diverging from the intent, basing your answers on my quick'n'dirty examples. I agree my examples are probably not the best looking, but there are no solutions right now to retrieve one part of th echain that failed, if not repeating the chain, and eventually thesame errors, on the right hand side. This is what `https://github.com/WebReflection/mice.trap#readme On Fri, Sep 6, 2019 at 2:48 PM Naveen Chawla wrote: > > I'm not in TC39, sorry if I sounded like I was, just voicing my opinion. > > I think the example you gave is better served by throwing the exception > from inside "query", instead of doing a "typeof" with the proposed operator > afterward. > > I find "type branching" normally to be a cumbersome logical flow. > Ordinarily the branching can be factored into a common "method" between the > types, so that logical flow doesn't need the branching at all (the method > "override" does it for you), but in the case of a "mouse" operator, you > could often be dealing with completely different types, for which a "common > method" may not make sense in the logical flow, thereby necessitating the > "type branching" featured in all your examples so far. > > To me "type branching" is a non-communicative style of programming. The > reader may not know the exact "type" of a particular property or > method/function's return value, even more so in JavaScript. Even worse if > the method may return different types depending on conditions. It is this > lack of clarity that I think can introduce bugs. The remedy, in my mind, is > a consistent (non-branching) logical flow. I think that language constructs > should encourage that type of programming and discourage type branching > (and other patterns that risk having a lack of logical clarity). > > Just my opinion, as I said. Disagreements welcome. > > On Fri, 6 Sep 2019 at 08:59, Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> The purpose is to address what chaining lacks, in terms of "stopping" at >> some point whenever it's available or not. >> >> Take this example: >> >> ```js >> // the current chaining operator >> const result = nmsp.some.payload()?.result ?? nmsp.some.payload(); >> >> // the mouse operator >> const result = nmsp.some.payload()> ``` >> >> Keeping it semantic, the mouse operator is "a trap" for the chain that >> makes reading possible expensive parts of the chain easier. An utility to >> obtain the same code would look something like the following: >> >> ```js >> // the mouse utility >> const mouse = trap => { >> // a way to self clean right after, as it is for RegExp.$* values >> // which is something impossible to obtain with regular syntax >> Promise.resolve(mouse.trap = trap).then(() => delete mouse.trap); >> return trap; >> }; >> >> // the previous example >> const result = mouse(nmsp.some.payload())?.result ?? mouse.trap; >> ``` >> >> Since there is no easy way to syntactically obtain the same with the >> current `?` and `??` without repeating all steps in the right side of the >> `??`, I've thought this "mouse operator" would play a role to actually >> avoid bugs easily introduced by repeating calls on the right hand side of >> the `??` either via getters or expensive operations. >> >> It is also possible to keep going on a chain or eventually provide >> feedbacks of what went wrong: >> >> ```js >> const name = await some.query(id)> if (typeof name !== 'string') >> throw name; >> ``` >> >> As summary, considering how semantic it's the operator in both visual and >> practical meanings, and considering it's not possible to achieve the same >> result through `??`, I wish it would be considered as complementary help >> for the recently introduced `?.` and `??` syntax. >> >> So thanks in advance for possible consideration. >> >> Regards >> >> >> On Fri, Sep 6, 2019 at 9:14 AM Naveen Chawla >> wrote: >> >>> I think introducing this operator encourages bad logic design like >>> "instanceof", isArray etc. These are unreadable disambiguation factors in >>> that they don't inform about which part the expression is going to the next >>> stage in the process. Also it leads to "type branching", which tends >>> towards more convoluted logical flow. These things, in my mind, would lead >>> to more bugs. Hence I would ten
Re: Optional chaining syntax but with the "mice" operator ?
The purpose is to address what chaining lacks, in terms of "stopping" at some point whenever it's available or not. Take this example: ```js // the current chaining operator const result = nmsp.some.payload()?.result ?? nmsp.some.payload(); // the mouse operator const result = nmsp.some.payload() { // a way to self clean right after, as it is for RegExp.$* values // which is something impossible to obtain with regular syntax Promise.resolve(mouse.trap = trap).then(() => delete mouse.trap); return trap; }; // the previous example const result = mouse(nmsp.some.payload())?.result ?? mouse.trap; ``` Since there is no easy way to syntactically obtain the same with the current `?` and `??` without repeating all steps in the right side of the `??`, I've thought this "mouse operator" would play a role to actually avoid bugs easily introduced by repeating calls on the right hand side of the `??` either via getters or expensive operations. It is also possible to keep going on a chain or eventually provide feedbacks of what went wrong: ```js const name = await some.query(id) wrote: > I think introducing this operator encourages bad logic design like > "instanceof", isArray etc. These are unreadable disambiguation factors in > that they don't inform about which part the expression is going to the next > stage in the process. Also it leads to "type branching", which tends > towards more convoluted logical flow. These things, in my mind, would lead > to more bugs. Hence I would tend to be against introducing it, especially > in light of other proposals that I find more useful that haven't been taken > even to discussion. > > On Fri, 6 Sep 2019, 07:58 Claude Pache, wrote: > >> >> >> Le 5 sept. 2019 à 23:39, Andrea Giammarchi >> a écrit : >> >> This is basically a solution to a common problem we have these days, >> where modules published in the wild might have a `default` property, to >> support ESM logic, or not. >> >> ```js >> // current optional chaining logic >> const imported = exported?.default ?? exported; >> >> // my "mice operator" proposal >> const imported = exported> ``` >> >> >> >> The semantics of the `?.` in `exported?.default` is not to check whether >> the `default` property exists, but whether `exported` evaluates to >> undefined or null. If the `default` property is absent, `exported.default` >> has always evaluated to `undefined`, and there is no need to optional >> chaining operator. So that I guess you actually meant: >> >> ``js >> const imported = exported.default ?? exported; >> ``` >> >> >> —Claude >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Optional chaining syntax but with the "mice" operator ?
As someone noticed already, the operator should be called eventually "mouse" operator, as mice is plural and was a misunderstand of mine 😅 On Fri, Sep 6, 2019, 00:54 Andrea Giammarchi wrote: > Since somebody asked me already elsewhere about the expected precedence of > the operator, this would be my answer: > > ```js > const result = await dbQuery(data) ``` > > would be the equivalent of > > ```js > let result = await dbQuery(data); > if (result != null && result.rows != null) > result = result.rows; > ``` > > or to better answer about precedence: > > ```js > const result = (await dbQuery(data)) ``` > > I hope this adds some extra context to this proposal. > > > On Fri, Sep 6, 2019 at 12:28 AM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> absolutely, I'm working with PostgreSQL these days and indeed for any >> promise/awaited result this pattern looks like a win, and while it's >> targeting a limitation of the chaining one, it can be used in various other >> cases where knowing the initial result is more important than just falling >> back to "_dunnoWhatHappenedThere_" >> >> On Fri, Sep 6, 2019 at 12:24 AM Michael Luder-Rosefield < >> rosyatran...@gmail.com> wrote: >> >>> Another pattern it could be useful in is with, say, nosql dbs where >>> something might be an object or id reference: >>> >>> ``` >>> const fooId = foo>> ``` >>> >>> On Thu, 5 Sep 2019, 23:03 Andrea Giammarchi, < >>> andrea.giammar...@gmail.com> wrote: >>> >>>> Another use case that I believe will be common is the following one: >>>> >>>> ```js >>>> // current state of the art >>>> const result = dbQuery(data)?.rows ?? 'did it just failed or what?'; >>>> >>>> // VS the "mice operator" >>>> const result = dbQuery(data)>>> >>>> // if it was rows >>>> if (Array.isArray(result)) >>>> console.log(result); >>>> else if (result instanceof Error) >>>> console.error(result.message); >>>> else >>>> console.warn(`unexpected result: ${result}`); >>>> ``` >>>> >>>> Ideally, the "mice" should grant chaining up to its latest presence, >>>> but I wouldn't know right now how to reference to it ... >>>> >>>> ```js >>>> // if no ?? is needed, this might work >>>> const result = dbQuery(data)>>> >>>> // if ?? is needed, no idea how to back-reference the latest >>>> successfull "mice" result >>>> ``` >>>> >>>> >>>> >>>> >>>> On Thu, Sep 5, 2019 at 11:44 PM Tab Atkins Jr. >>>> wrote: >>>> >>>>> On Thu, Sep 5, 2019 at 2:39 PM Andrea Giammarchi >>>>> wrote: >>>>> > >>>>> > This is basically a solution to a common problem we have these days, >>>>> where modules published in the wild might have a `default` property, to >>>>> support ESM logic, or not. >>>>> > >>>>> > ```js >>>>> > // current optional chaining logic >>>>> > const imported = exported?.default ?? exported; >>>>> > >>>>> > // my "mice operator" proposal >>>>> > const imported = exported>>>> > ``` >>>>> > >>>>> > Semantically speaking, not only `>>>> also points at its previous value in case the chaining didn't work. >>>>> > >>>>> > Beside the basic example, the "mice operator" might save CPU cycles >>>>> when it comes to involving more complex expressions, i.e. >>>>> > >>>>> > ```js >>>>> > // current "solution" >>>>> > const thing = require('thing')?.default ?? require('thing'); >>>>> > >>>>> > // mice operator >>>>> > const thing = require('thing')>>>> > ``` >>>>> > >>>>> > This is also easily tranpilable, so kinda a no-brainer for modern >>>>> dev tools to bring in. >>>>> > >>>>> > TL;DR specially for cases where an accessed property should fallback >>>>> to its source, this operator might save both typing and CPU time whenever >>>>> it's needed. >>>>> >>>>> I find it a rather curious pattern, that I'd never seen before! Is it >>>>> used in anything besides this ESM-compat thing you're talking about? >>>>> >>>>> (Saving CPU cycles is not a convincing argument; it's trivial to write >>>>> such a line over two declarations and avoid any expensive >>>>> recomputations.) >>>>> >>>>> ~TJ >>>>> >>>> ___ >>>> es-discuss mailing list >>>> es-discuss@mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Optional chaining syntax but with the "mice" operator ?
Since somebody asked me already elsewhere about the expected precedence of the operator, this would be my answer: ```js const result = await dbQuery(data) wrote: > absolutely, I'm working with PostgreSQL these days and indeed for any > promise/awaited result this pattern looks like a win, and while it's > targeting a limitation of the chaining one, it can be used in various other > cases where knowing the initial result is more important than just falling > back to "_dunnoWhatHappenedThere_" > > On Fri, Sep 6, 2019 at 12:24 AM Michael Luder-Rosefield < > rosyatran...@gmail.com> wrote: > >> Another pattern it could be useful in is with, say, nosql dbs where >> something might be an object or id reference: >> >> ``` >> const fooId = foo> ``` >> >> On Thu, 5 Sep 2019, 23:03 Andrea Giammarchi, >> wrote: >> >>> Another use case that I believe will be common is the following one: >>> >>> ```js >>> // current state of the art >>> const result = dbQuery(data)?.rows ?? 'did it just failed or what?'; >>> >>> // VS the "mice operator" >>> const result = dbQuery(data)>> >>> // if it was rows >>> if (Array.isArray(result)) >>> console.log(result); >>> else if (result instanceof Error) >>> console.error(result.message); >>> else >>> console.warn(`unexpected result: ${result}`); >>> ``` >>> >>> Ideally, the "mice" should grant chaining up to its latest presence, but >>> I wouldn't know right now how to reference to it ... >>> >>> ```js >>> // if no ?? is needed, this might work >>> const result = dbQuery(data)>> >>> // if ?? is needed, no idea how to back-reference the latest successfull >>> "mice" result >>> ``` >>> >>> >>> >>> >>> On Thu, Sep 5, 2019 at 11:44 PM Tab Atkins Jr. >>> wrote: >>> >>>> On Thu, Sep 5, 2019 at 2:39 PM Andrea Giammarchi >>>> wrote: >>>> > >>>> > This is basically a solution to a common problem we have these days, >>>> where modules published in the wild might have a `default` property, to >>>> support ESM logic, or not. >>>> > >>>> > ```js >>>> > // current optional chaining logic >>>> > const imported = exported?.default ?? exported; >>>> > >>>> > // my "mice operator" proposal >>>> > const imported = exported>>> > ``` >>>> > >>>> > Semantically speaking, not only `>>> also points at its previous value in case the chaining didn't work. >>>> > >>>> > Beside the basic example, the "mice operator" might save CPU cycles >>>> when it comes to involving more complex expressions, i.e. >>>> > >>>> > ```js >>>> > // current "solution" >>>> > const thing = require('thing')?.default ?? require('thing'); >>>> > >>>> > // mice operator >>>> > const thing = require('thing')>>> > ``` >>>> > >>>> > This is also easily tranpilable, so kinda a no-brainer for modern dev >>>> tools to bring in. >>>> > >>>> > TL;DR specially for cases where an accessed property should fallback >>>> to its source, this operator might save both typing and CPU time whenever >>>> it's needed. >>>> >>>> I find it a rather curious pattern, that I'd never seen before! Is it >>>> used in anything besides this ESM-compat thing you're talking about? >>>> >>>> (Saving CPU cycles is not a convincing argument; it's trivial to write >>>> such a line over two declarations and avoid any expensive >>>> recomputations.) >>>> >>>> ~TJ >>>> >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Optional chaining syntax but with the "mice" operator ?
absolutely, I'm working with PostgreSQL these days and indeed for any promise/awaited result this pattern looks like a win, and while it's targeting a limitation of the chaining one, it can be used in various other cases where knowing the initial result is more important than just falling back to "_dunnoWhatHappenedThere_" On Fri, Sep 6, 2019 at 12:24 AM Michael Luder-Rosefield < rosyatran...@gmail.com> wrote: > Another pattern it could be useful in is with, say, nosql dbs where > something might be an object or id reference: > > ``` > const fooId = foo ``` > > On Thu, 5 Sep 2019, 23:03 Andrea Giammarchi, > wrote: > >> Another use case that I believe will be common is the following one: >> >> ```js >> // current state of the art >> const result = dbQuery(data)?.rows ?? 'did it just failed or what?'; >> >> // VS the "mice operator" >> const result = dbQuery(data)> >> // if it was rows >> if (Array.isArray(result)) >> console.log(result); >> else if (result instanceof Error) >> console.error(result.message); >> else >> console.warn(`unexpected result: ${result}`); >> ``` >> >> Ideally, the "mice" should grant chaining up to its latest presence, but >> I wouldn't know right now how to reference to it ... >> >> ```js >> // if no ?? is needed, this might work >> const result = dbQuery(data)> >> // if ?? is needed, no idea how to back-reference the latest successfull >> "mice" result >> ``` >> >> >> >> >> On Thu, Sep 5, 2019 at 11:44 PM Tab Atkins Jr. >> wrote: >> >>> On Thu, Sep 5, 2019 at 2:39 PM Andrea Giammarchi >>> wrote: >>> > >>> > This is basically a solution to a common problem we have these days, >>> where modules published in the wild might have a `default` property, to >>> support ESM logic, or not. >>> > >>> > ```js >>> > // current optional chaining logic >>> > const imported = exported?.default ?? exported; >>> > >>> > // my "mice operator" proposal >>> > const imported = exported>> > ``` >>> > >>> > Semantically speaking, not only `>> also points at its previous value in case the chaining didn't work. >>> > >>> > Beside the basic example, the "mice operator" might save CPU cycles >>> when it comes to involving more complex expressions, i.e. >>> > >>> > ```js >>> > // current "solution" >>> > const thing = require('thing')?.default ?? require('thing'); >>> > >>> > // mice operator >>> > const thing = require('thing')>> > ``` >>> > >>> > This is also easily tranpilable, so kinda a no-brainer for modern dev >>> tools to bring in. >>> > >>> > TL;DR specially for cases where an accessed property should fallback >>> to its source, this operator might save both typing and CPU time whenever >>> it's needed. >>> >>> I find it a rather curious pattern, that I'd never seen before! Is it >>> used in anything besides this ESM-compat thing you're talking about? >>> >>> (Saving CPU cycles is not a convincing argument; it's trivial to write >>> such a line over two declarations and avoid any expensive >>> recomputations.) >>> >>> ~TJ >>> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Optional chaining syntax but with the "mice" operator ?
Another use case that I believe will be common is the following one: ```js // current state of the art const result = dbQuery(data)?.rows ?? 'did it just failed or what?'; // VS the "mice operator" const result = dbQuery(data) wrote: > On Thu, Sep 5, 2019 at 2:39 PM Andrea Giammarchi > wrote: > > > > This is basically a solution to a common problem we have these days, > where modules published in the wild might have a `default` property, to > support ESM logic, or not. > > > > ```js > > // current optional chaining logic > > const imported = exported?.default ?? exported; > > > > // my "mice operator" proposal > > const imported = exported > ``` > > > > Semantically speaking, not only ` points at its previous value in case the chaining didn't work. > > > > Beside the basic example, the "mice operator" might save CPU cycles when > it comes to involving more complex expressions, i.e. > > > > ```js > > // current "solution" > > const thing = require('thing')?.default ?? require('thing'); > > > > // mice operator > > const thing = require('thing') > ``` > > > > This is also easily tranpilable, so kinda a no-brainer for modern dev > tools to bring in. > > > > TL;DR specially for cases where an accessed property should fallback to > its source, this operator might save both typing and CPU time whenever it's > needed. > > I find it a rather curious pattern, that I'd never seen before! Is it > used in anything besides this ESM-compat thing you're talking about? > > (Saving CPU cycles is not a convincing argument; it's trivial to write > such a line over two declarations and avoid any expensive > recomputations.) > > ~TJ > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Optional chaining syntax but with the "mice" operator ?
This is basically a solution to a common problem we have these days, where modules published in the wild might have a `default` property, to support ESM logic, or not. ```js // current optional chaining logic const imported = exported?.default ?? exported; // my "mice operator" proposal const imported = exported___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Array.prototype.joinWith(iterable)
Naveen, please read more about template literals tags, thanks. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates On Mon, Aug 19, 2019 at 12:16 PM Naveen Chawla wrote: > HTML tags? Afraid I still don't get that aspect. Perhaps my reading style > is not matching your writing style. I understood everything else. I would > still need a really simple example(/s) completed with sample input data > from start to finish (for tags). > > Anyway from what I'm seeing so far I think "weave" is a better name than > "joinWith". > > On Mon, 19 Aug 2019 at 09:56, Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> A lot of libraries flatten template tags for a reason or another. The JSX >> oriented `htm` project [1], as example, does that to obtain a single key, >> since TypeScript has broken template literals, and avoiding duplicated work >> per same literal is a common template tag based libraries use case. >> >> Here the code: >> https://github.com/developit/htm/blob/master/src/index.mjs#L25-L31 >> >> That could be `template[0].length + '-' + >> template.joinWith(template.map(chunk => chunk.length + '-'))` >> >> Dummy no-op functions (this is only an example >> https://github.com/WebReflection/i18n-dummy/blob/master/esm/main.js) are >> also common, + I've used myself the pattern over and over in various >> occasions, where you can use a generic function either as regular or as a >> tag. >> >> Accordingly, the simplification would be handy already, and extra use >> cases, as the one used with the date separator, or any other similar one, >> shows possible new ways to easily join arbitrary amount of data. >> >> Because of these previous points, I've thought proposing this was worth a >> shot. >> >> [1] https://github.com/developit/htm >> >> >> On Fri, Aug 16, 2019 at 10:00 PM Jordan Harband wrote: >> >>> Can you elaborate a bit more on how this is a *common* case in the wider >>> ecosystem? >>> >>> On Fri, Aug 16, 2019 at 5:29 AM Andrea Giammarchi < >>> andrea.giammar...@gmail.com> wrote: >>> >>>> early reply "which otehr cases"? this is just an example: >>>> >>>> [2019, 08, 16, 14, 28, 30].map(i => i < 10 ? ('0' + i) : >>>> i).joinWith('--T::.'); >>>> >>>> On Fri, Aug 16, 2019 at 2:24 PM Andrea Giammarchi < >>>> andrea.giammar...@gmail.com> wrote: >>>> >>>>> `this ${Symbol('throws')} an error`, so anything that cannot be >>>>> represented as string should throw too, as it is for `[1, 2, >>>>> 3].join(Symbol())`. >>>>> >>>>> In few words, everything described as parameter for the >>>>> `Array.prototype.join(param)` should be described as the iterable value, >>>>> nothng new to add, nothing different to expect. >>>>> >>>>> The template literal as is returns a string, but if you use tags, as >>>>> functions, you deal with an array and a collection or extra values (0 to >>>>> template.length - 1). >>>>> >>>>> The current way to flatten a template via tag, used already in various >>>>> projects for a reason or another, is the following one: >>>>> >>>>> ```js >>>>> function tag2str(template) { >>>>> let str = template[0]; >>>>> for (let i = 1, t = template.length; i < t; i++) >>>>> str += arguments[i] + template[i]; >>>>> return str; >>>>> } >>>>> ``` >>>>> >>>>> I am proposing to simplify this common case with something that could >>>>> be used for other cases too. >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> On Fri, Aug 16, 2019 at 1:17 PM Naveen Chawla >>>>> wrote: >>>>> >>>>>> Cool. >>>>>> >>>>>> I get it now apart from the "templated string" example. I'm not very >>>>>> knowledgable about templated strings but on the face it looks like >>>>>> 'a${x}b${y}' already inserts x and y into the string, so I'm not sure >>>>>> what >>>>>> else is happening with your proposed method? Clearly I've missed >>>>
Re: Array.prototype.joinWith(iterable)
A lot of libraries flatten template tags for a reason or another. The JSX oriented `htm` project [1], as example, does that to obtain a single key, since TypeScript has broken template literals, and avoiding duplicated work per same literal is a common template tag based libraries use case. Here the code: https://github.com/developit/htm/blob/master/src/index.mjs#L25-L31 That could be `template[0].length + '-' + template.joinWith(template.map(chunk => chunk.length + '-'))` Dummy no-op functions (this is only an example https://github.com/WebReflection/i18n-dummy/blob/master/esm/main.js) are also common, + I've used myself the pattern over and over in various occasions, where you can use a generic function either as regular or as a tag. Accordingly, the simplification would be handy already, and extra use cases, as the one used with the date separator, or any other similar one, shows possible new ways to easily join arbitrary amount of data. Because of these previous points, I've thought proposing this was worth a shot. [1] https://github.com/developit/htm On Fri, Aug 16, 2019 at 10:00 PM Jordan Harband wrote: > Can you elaborate a bit more on how this is a *common* case in the wider > ecosystem? > > On Fri, Aug 16, 2019 at 5:29 AM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> early reply "which otehr cases"? this is just an example: >> >> [2019, 08, 16, 14, 28, 30].map(i => i < 10 ? ('0' + i) : >> i).joinWith('--T::.'); >> >> On Fri, Aug 16, 2019 at 2:24 PM Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> `this ${Symbol('throws')} an error`, so anything that cannot be >>> represented as string should throw too, as it is for `[1, 2, >>> 3].join(Symbol())`. >>> >>> In few words, everything described as parameter for the >>> `Array.prototype.join(param)` should be described as the iterable value, >>> nothng new to add, nothing different to expect. >>> >>> The template literal as is returns a string, but if you use tags, as >>> functions, you deal with an array and a collection or extra values (0 to >>> template.length - 1). >>> >>> The current way to flatten a template via tag, used already in various >>> projects for a reason or another, is the following one: >>> >>> ```js >>> function tag2str(template) { >>> let str = template[0]; >>> for (let i = 1, t = template.length; i < t; i++) >>> str += arguments[i] + template[i]; >>> return str; >>> } >>> ``` >>> >>> I am proposing to simplify this common case with something that could be >>> used for other cases too. >>> >>> >>> >>> >>> >>> On Fri, Aug 16, 2019 at 1:17 PM Naveen Chawla >>> wrote: >>> >>>> Cool. >>>> >>>> I get it now apart from the "templated string" example. I'm not very >>>> knowledgable about templated strings but on the face it looks like >>>> 'a${x}b${y}' already inserts x and y into the string, so I'm not sure what >>>> else is happening with your proposed method? Clearly I've missed something. >>>> >>>> Apart from that, how would you handle arrays that whose values are not >>>> all strings? >>>> >>>> For naming is still think "weave" would be OK from what I know so far >>>> >>>> On Fri, 16 Aug 2019 at 11:08, Andrea Giammarchi < >>>> andrea.giammar...@gmail.com> wrote: >>>> >>>>> given an array, it joins it through the values of the iterable >>>>> argument, without ever resulting to undefined >>>>> >>>>> ['a', 'b', 'c'].joinWith(['-']) would produce "a-b-c" >>>>> >>>>> ['a', 'b', 'c'].joinWith([1, 2]) would produce "a1b2c" >>>>> >>>>> ['a', 'b', 'c'].joinWith('012') would produce "a0b1c" >>>>> note the string, as iterable, is acceptable too >>>>> >>>>> const tag = (template, ...values) => template.joinWith(values); >>>>> tag`a${Math.random()}b${Math.random()}`; would fill the gap between a >>>>> and b, or b and c, with the value returned by the two Math.random() >>>>> >>>>> ['a', 'b', 'c', 'd&
Re: Array.prototype.joinWith(iterable)
early reply "which otehr cases"? this is just an example: [2019, 08, 16, 14, 28, 30].map(i => i < 10 ? ('0' + i) : i).joinWith('--T::.'); On Fri, Aug 16, 2019 at 2:24 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > `this ${Symbol('throws')} an error`, so anything that cannot be > represented as string should throw too, as it is for `[1, 2, > 3].join(Symbol())`. > > In few words, everything described as parameter for the > `Array.prototype.join(param)` should be described as the iterable value, > nothng new to add, nothing different to expect. > > The template literal as is returns a string, but if you use tags, as > functions, you deal with an array and a collection or extra values (0 to > template.length - 1). > > The current way to flatten a template via tag, used already in various > projects for a reason or another, is the following one: > > ```js > function tag2str(template) { > let str = template[0]; > for (let i = 1, t = template.length; i < t; i++) > str += arguments[i] + template[i]; > return str; > } > ``` > > I am proposing to simplify this common case with something that could be > used for other cases too. > > > > > > On Fri, Aug 16, 2019 at 1:17 PM Naveen Chawla > wrote: > >> Cool. >> >> I get it now apart from the "templated string" example. I'm not very >> knowledgable about templated strings but on the face it looks like >> 'a${x}b${y}' already inserts x and y into the string, so I'm not sure what >> else is happening with your proposed method? Clearly I've missed something. >> >> Apart from that, how would you handle arrays that whose values are not >> all strings? >> >> For naming is still think "weave" would be OK from what I know so far >> >> On Fri, 16 Aug 2019 at 11:08, Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> given an array, it joins it through the values of the iterable argument, >>> without ever resulting to undefined >>> >>> ['a', 'b', 'c'].joinWith(['-']) would produce "a-b-c" >>> >>> ['a', 'b', 'c'].joinWith([1, 2]) would produce "a1b2c" >>> >>> ['a', 'b', 'c'].joinWith('012') would produce "a0b1c" >>> note the string, as iterable, is acceptable too >>> >>> const tag = (template, ...values) => template.joinWith(values); >>> tag`a${Math.random()}b${Math.random()}`; would fill the gap between a >>> and b, or b and c, with the value returned by the two Math.random() >>> >>> ['a', 'b', 'c', 'd'].joinWith('01'); would produce "a0b1c0d" so that >>> there's never an `undefined >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> On Fri, Aug 16, 2019 at 12:01 PM Naveen Chawla >>> wrote: >>> >>>> I'm just not seeing what it's supposed to do. If you could give a brief >>>> explanation of the array method, and the string method then of course I >>>> would get it. I know it would seem obvious to you from the examples alone, >>>> it's just not to me. >>>> >>>> On Fri, 16 Aug 2019 at 08:32, Andrea Giammarchi < >>>> andrea.giammar...@gmail.com> wrote: >>>> >>>>> Just to re-state: zip from lowdash, does **not** do what my proposed >>>>> method does ... anything that won't produce the following result is not >>>>> what I'm proposing >>>>> >>>>> console.log(['a', 'b', 'c', 'd'].joinWith([1, 2])); >>>>> // a1b2c1d >>>>> >>>>> function tag2str(template, ...values) { >>>>> return template.joinWith(values); >>>>> } >>>>> >>>>> tag2str`a${1}b${2}c`; >>>>> // "a1b2c" >>>>> >>>>> On Fri, Aug 16, 2019 at 5:57 AM Isiah Meadows >>>>> wrote: >>>>> >>>>>> For that, I'd rather see an `interleave` that just rotates through all >>>>>> its arguments. It'd be basically sugar for `.zip().flat()`, but an >>>>>> implementation could optimize the heck out of it. (In particular, they >>>>>> could iterate through them
Re: Array.prototype.joinWith(iterable)
`this ${Symbol('throws')} an error`, so anything that cannot be represented as string should throw too, as it is for `[1, 2, 3].join(Symbol())`. In few words, everything described as parameter for the `Array.prototype.join(param)` should be described as the iterable value, nothng new to add, nothing different to expect. The template literal as is returns a string, but if you use tags, as functions, you deal with an array and a collection or extra values (0 to template.length - 1). The current way to flatten a template via tag, used already in various projects for a reason or another, is the following one: ```js function tag2str(template) { let str = template[0]; for (let i = 1, t = template.length; i < t; i++) str += arguments[i] + template[i]; return str; } ``` I am proposing to simplify this common case with something that could be used for other cases too. On Fri, Aug 16, 2019 at 1:17 PM Naveen Chawla wrote: > Cool. > > I get it now apart from the "templated string" example. I'm not very > knowledgable about templated strings but on the face it looks like > 'a${x}b${y}' already inserts x and y into the string, so I'm not sure what > else is happening with your proposed method? Clearly I've missed something. > > Apart from that, how would you handle arrays that whose values are not all > strings? > > For naming is still think "weave" would be OK from what I know so far > > On Fri, 16 Aug 2019 at 11:08, Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> given an array, it joins it through the values of the iterable argument, >> without ever resulting to undefined >> >> ['a', 'b', 'c'].joinWith(['-']) would produce "a-b-c" >> >> ['a', 'b', 'c'].joinWith([1, 2]) would produce "a1b2c" >> >> ['a', 'b', 'c'].joinWith('012') would produce "a0b1c" >> note the string, as iterable, is acceptable too >> >> const tag = (template, ...values) => template.joinWith(values); >> tag`a${Math.random()}b${Math.random()}`; would fill the gap between a and >> b, or b and c, with the value returned by the two Math.random() >> >> ['a', 'b', 'c', 'd'].joinWith('01'); would produce "a0b1c0d" so that >> there's never an `undefined >> >> >> >> >> >> >> >> >> >> On Fri, Aug 16, 2019 at 12:01 PM Naveen Chawla >> wrote: >> >>> I'm just not seeing what it's supposed to do. If you could give a brief >>> explanation of the array method, and the string method then of course I >>> would get it. I know it would seem obvious to you from the examples alone, >>> it's just not to me. >>> >>> On Fri, 16 Aug 2019 at 08:32, Andrea Giammarchi < >>> andrea.giammar...@gmail.com> wrote: >>> >>>> Just to re-state: zip from lowdash, does **not** do what my proposed >>>> method does ... anything that won't produce the following result is not >>>> what I'm proposing >>>> >>>> console.log(['a', 'b', 'c', 'd'].joinWith([1, 2])); >>>> // a1b2c1d >>>> >>>> function tag2str(template, ...values) { >>>> return template.joinWith(values); >>>> } >>>> >>>> tag2str`a${1}b${2}c`; >>>> // "a1b2c" >>>> >>>> On Fri, Aug 16, 2019 at 5:57 AM Isiah Meadows >>>> wrote: >>>> >>>>> For that, I'd rather see an `interleave` that just rotates through all >>>>> its arguments. It'd be basically sugar for `.zip().flat()`, but an >>>>> implementation could optimize the heck out of it. (In particular, they >>>>> could iterate through them one-by-one and only allocate once, not in >>>>> the hot loop, so it'd be fast.) >>>>> >>>>> I at one point had it in my list of wishlist proposals, but it somehow >>>>> disappeared. I've since recreated it: >>>>> >>>>> https://github.com/isiahmeadows/es-stdlib-proposals/blob/master/proposals/array/interleave.md >>>>> >>>>> - >>>>> >>>>> Isiah Meadows >>>>> cont...@isiahmeadows.com >>>>> www.isiahmeadows.com >>>>> >>>>> >>>>> On Thu, Aug 15, 2019 at 1:12 PM Andrea Giammarchi >&g
Re: Array.prototype.joinWith(iterable)
given an array, it joins it through the values of the iterable argument, without ever resulting to undefined ['a', 'b', 'c'].joinWith(['-']) would produce "a-b-c" ['a', 'b', 'c'].joinWith([1, 2]) would produce "a1b2c" ['a', 'b', 'c'].joinWith('012') would produce "a0b1c" note the string, as iterable, is acceptable too const tag = (template, ...values) => template.joinWith(values); tag`a${Math.random()}b${Math.random()}`; would fill the gap between a and b, or b and c, with the value returned by the two Math.random() ['a', 'b', 'c', 'd'].joinWith('01'); would produce "a0b1c0d" so that there's never an `undefined On Fri, Aug 16, 2019 at 12:01 PM Naveen Chawla wrote: > I'm just not seeing what it's supposed to do. If you could give a brief > explanation of the array method, and the string method then of course I > would get it. I know it would seem obvious to you from the examples alone, > it's just not to me. > > On Fri, 16 Aug 2019 at 08:32, Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> Just to re-state: zip from lowdash, does **not** do what my proposed >> method does ... anything that won't produce the following result is not >> what I'm proposing >> >> console.log(['a', 'b', 'c', 'd'].joinWith([1, 2])); >> // a1b2c1d >> >> function tag2str(template, ...values) { >> return template.joinWith(values); >> } >> >> tag2str`a${1}b${2}c`; >> // "a1b2c" >> >> On Fri, Aug 16, 2019 at 5:57 AM Isiah Meadows >> wrote: >> >>> For that, I'd rather see an `interleave` that just rotates through all >>> its arguments. It'd be basically sugar for `.zip().flat()`, but an >>> implementation could optimize the heck out of it. (In particular, they >>> could iterate through them one-by-one and only allocate once, not in >>> the hot loop, so it'd be fast.) >>> >>> I at one point had it in my list of wishlist proposals, but it somehow >>> disappeared. I've since recreated it: >>> >>> https://github.com/isiahmeadows/es-stdlib-proposals/blob/master/proposals/array/interleave.md >>> >>> - >>> >>> Isiah Meadows >>> cont...@isiahmeadows.com >>> www.isiahmeadows.com >>> >>> >>> On Thu, Aug 15, 2019 at 1:12 PM Andrea Giammarchi >>> wrote: >>> > >>> > That;s not useful for template literals tags though >>> > >>> > _.zip(['a', 'b', 'c'], [1, 2]); >>> > [["a", 1], ["b", 2], ["c", undefined]] >>> > >>> > it basically does nothing I've proposed ... any other name suggestion? >>> > >>> > On Thu, Aug 15, 2019 at 3:40 PM Michał Wadas >>> wrote: >>> >> >>> >> https://lodash.com/docs/#zip >>> >> https://docs.python.org/3/library/functions.html#zip >>> >> >>> >> On Thu, 15 Aug 2019, 15:34 Andrea Giammarchi, < >>> andrea.giammar...@gmail.com> wrote: >>> >>> >>> >>> the suggested name is just ... suggested, I don't have strong >>> opinion on it, it just `join` values through other values >>> >>> what's `Array.zip` ? I've no idea >>> >>> >>> >>> >>> >>> On Thu, Aug 15, 2019 at 12:53 PM Michał Wadas >>> wrote: >>> >>>> >>> >>>> I would rather see Array.zip, it covers this use case. >>> >>>> >>> >>>> On Thu, 15 Aug 2019, 10:50 Andrea Giammarchi, < >>> andrea.giammar...@gmail.com> wrote: >>> >>>>> >>> >>>>> >>> >>>>> I wonder if there's any interest in adding another handy Array >>> method as joinWith could be: >>> >>>>> >>> >>>>> ```js >>> >>>>> // proposal example >>> >>>>> Array.prototype.joinWith = function (values) { >>> >>>>> const {length} = this; >>> >>>>> if (length < 2) >>> >>>>> return this.join(''); >>> >>>>> const out = [this[0]]; >>> >>>>> const len = values.length; >>> >>>>> for (let i = 1; i < length; i++) { >>> >>>>> console.log(i, len); >>> >>>>> out.push(values[(i - 1) % len], this[i]); >>> >>>>> } >>> >>>>> return out.join(''); >>> >>>>> }; >>> >>>>> ``` >>> >>>>> >>> >>>>> The goal is to simplify joining array entries through not the same >>> value, example: >>> >>>>> >>> >>>>> ```js >>> >>>>> console.log(['a', 'b', 'c', 'd'].joinWith([1, 2])); >>> >>>>> // a1b2c1d >>> >>>>> >>> >>>>> function tag2str(template, ...values) { >>> >>>>> return template.joinWith(values); >>> >>>>> } >>> >>>>> >>> >>>>> tag2str`a${1}b${2}c`; >>> >>>>> // "a1b2c" >>> >>>>> ``` >>> >>>>> >>> >>>>> Throughts? >>> >>>>> ___ >>> >>>>> es-discuss mailing list >>> >>>>> es-discuss@mozilla.org >>> >>>>> https://mail.mozilla.org/listinfo/es-discuss >>> > >>> > ___ >>> > es-discuss mailing list >>> > es-discuss@mozilla.org >>> > https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Array.prototype.joinWith(iterable)
Just to re-state: zip from lowdash, does **not** do what my proposed method does ... anything that won't produce the following result is not what I'm proposing console.log(['a', 'b', 'c', 'd'].joinWith([1, 2])); // a1b2c1d function tag2str(template, ...values) { return template.joinWith(values); } tag2str`a${1}b${2}c`; // "a1b2c" On Fri, Aug 16, 2019 at 5:57 AM Isiah Meadows wrote: > For that, I'd rather see an `interleave` that just rotates through all > its arguments. It'd be basically sugar for `.zip().flat()`, but an > implementation could optimize the heck out of it. (In particular, they > could iterate through them one-by-one and only allocate once, not in > the hot loop, so it'd be fast.) > > I at one point had it in my list of wishlist proposals, but it somehow > disappeared. I've since recreated it: > > https://github.com/isiahmeadows/es-stdlib-proposals/blob/master/proposals/array/interleave.md > > ----- > > Isiah Meadows > cont...@isiahmeadows.com > www.isiahmeadows.com > > > On Thu, Aug 15, 2019 at 1:12 PM Andrea Giammarchi > wrote: > > > > That;s not useful for template literals tags though > > > > _.zip(['a', 'b', 'c'], [1, 2]); > > [["a", 1], ["b", 2], ["c", undefined]] > > > > it basically does nothing I've proposed ... any other name suggestion? > > > > On Thu, Aug 15, 2019 at 3:40 PM Michał Wadas > wrote: > >> > >> https://lodash.com/docs/#zip > >> https://docs.python.org/3/library/functions.html#zip > >> > >> On Thu, 15 Aug 2019, 15:34 Andrea Giammarchi, < > andrea.giammar...@gmail.com> wrote: > >>> > >>> the suggested name is just ... suggested, I don't have strong opinion > on it, it just `join` values through other values > >>> what's `Array.zip` ? I've no idea > >>> > >>> > >>> On Thu, Aug 15, 2019 at 12:53 PM Michał Wadas > wrote: > >>>> > >>>> I would rather see Array.zip, it covers this use case. > >>>> > >>>> On Thu, 15 Aug 2019, 10:50 Andrea Giammarchi, < > andrea.giammar...@gmail.com> wrote: > >>>>> > >>>>> > >>>>> I wonder if there's any interest in adding another handy Array > method as joinWith could be: > >>>>> > >>>>> ```js > >>>>> // proposal example > >>>>> Array.prototype.joinWith = function (values) { > >>>>> const {length} = this; > >>>>> if (length < 2) > >>>>> return this.join(''); > >>>>> const out = [this[0]]; > >>>>> const len = values.length; > >>>>> for (let i = 1; i < length; i++) { > >>>>> console.log(i, len); > >>>>> out.push(values[(i - 1) % len], this[i]); > >>>>> } > >>>>> return out.join(''); > >>>>> }; > >>>>> ``` > >>>>> > >>>>> The goal is to simplify joining array entries through not the same > value, example: > >>>>> > >>>>> ```js > >>>>> console.log(['a', 'b', 'c', 'd'].joinWith([1, 2])); > >>>>> // a1b2c1d > >>>>> > >>>>> function tag2str(template, ...values) { > >>>>> return template.joinWith(values); > >>>>> } > >>>>> > >>>>> tag2str`a${1}b${2}c`; > >>>>> // "a1b2c" > >>>>> ``` > >>>>> > >>>>> Throughts? > >>>>> ___ > >>>>> es-discuss mailing list > >>>>> es-discuss@mozilla.org > >>>>> https://mail.mozilla.org/listinfo/es-discuss > > > > ___ > > es-discuss mailing list > > es-discuss@mozilla.org > > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Array.prototype.findIndex(fn, startIndex = 0)
isn't the second argument already reserved for the context? ```js [1, 2, 3].findIndex(function (i) { return i == this; }, 2); // 1 ``` On Thu, Aug 15, 2019 at 11:51 PM Cyril Auburtin wrote: > It should be possible to add a second optional argument to the `find` and > `findIndex` array methods, similarly to `indexOf` > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Array.prototype.joinWith(iterable)
There is a whole example that produces a string, like join does, using the second argument iterable to fill the "junctions" ... which part is not clear in the test case? ```js console.log(['a', 'b', 'c', 'd'].joinWith([1, 2])); // a1b2c1d function tag2str(template, ...values) { return template.joinWith(values); } tag2str`a${1}b${2}c`; // "a1b2c" ``` On Thu, Aug 15, 2019 at 7:39 PM Naveen Chawla wrote: > "weave"? (I've likely missed the purpose of the method) > > On Thu, 15 Aug 2019, 18:12 Andrea Giammarchi, > wrote: > >> That;s not useful for template literals tags though >> >> _.zip(['a', 'b', 'c'], [1, 2]); >> [["a", 1], ["b", 2], ["c", undefined]] >> >> it basically does nothing I've proposed ... any other name suggestion? >> >> On Thu, Aug 15, 2019 at 3:40 PM Michał Wadas >> wrote: >> >>> https://lodash.com/docs/#zip >>> https://docs.python.org/3/library/functions.html#zip >>> >>> On Thu, 15 Aug 2019, 15:34 Andrea Giammarchi, < >>> andrea.giammar...@gmail.com> wrote: >>> >>>> >>>>1. the suggested name is just ... suggested, I don't have strong >>>>opinion on it, it just `join` values through other values >>>>2. what's `Array.zip` ? I've no idea >>>> >>>> >>>> On Thu, Aug 15, 2019 at 12:53 PM Michał Wadas >>>> wrote: >>>> >>>>> I would rather see Array.zip, it covers this use case. >>>>> >>>>> On Thu, 15 Aug 2019, 10:50 Andrea Giammarchi, < >>>>> andrea.giammar...@gmail.com> wrote: >>>>> >>>>>> >>>>>> I wonder if there's any interest in adding another handy Array method >>>>>> as joinWith could be: >>>>>> >>>>>> ```js >>>>>> // proposal example >>>>>> Array.prototype.joinWith = function (values) { >>>>>> const {length} = this; >>>>>> if (length < 2) >>>>>> return this.join(''); >>>>>> const out = [this[0]]; >>>>>> const len = values.length; >>>>>> for (let i = 1; i < length; i++) { >>>>>> console.log(i, len); >>>>>> out.push(values[(i - 1) % len], this[i]); >>>>>> } >>>>>> return out.join(''); >>>>>> }; >>>>>> ``` >>>>>> >>>>>> The goal is to simplify joining array entries through not the same >>>>>> value, example: >>>>>> >>>>>> ```js >>>>>> console.log(['a', 'b', 'c', 'd'].joinWith([1, 2])); >>>>>> // a1b2c1d >>>>>> >>>>>> function tag2str(template, ...values) { >>>>>> return template.joinWith(values); >>>>>> } >>>>>> >>>>>> tag2str`a${1}b${2}c`; >>>>>> // "a1b2c" >>>>>> ``` >>>>>> >>>>>> Throughts? >>>>>> ___ >>>>>> es-discuss mailing list >>>>>> es-discuss@mozilla.org >>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>> >>>>> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Modulo Operator %%
Fair points, but since `**` has its `Math.pow` counter part, why wouldn't `%%` have `Math.mod` as counterpart too? At least it looks like there's room for both, if standardized, as the behavior and description would likely be mostly the same (precedence a part) On Thu, Aug 15, 2019 at 7:13 PM Isiah Meadows wrote: > An operator is far more concise than a function call, and is likely to > see greater use. It also aligns better with peoples' intuition on what > the "modulus" is, avoiding subtle bugs like in `isOdd = x => x % 2 === > 1` (example from > https://en.wikipedia.org/wiki/Modulo_operation#Common_pitfalls - try > passing a negative to it). And given this one is high value (see > above) and *very* low cost (it can literally desugar to `(x % y + y) % > y`), I feel it does meet that bar. > > > It would be interesting to hear the feedback of those that use regularly > powers, whether the benefit was clear (personally, I almost never use > either `Math.pow()` or `**`, so that I can’t say anything). > > It has enough benefit I've seen CoffeeScript users default to `%%` and > only using `%` when they explicitly want the dividend-dependent > semantics. And engines with a native `%%`, if they can detect the > operands are always non-negative, can optimize it to `%` pretty > easily. It's better *enough* that you'd likely start seeing some > partially legitimate FUD spread about the standard `%`. > > One other added benefit of using divisor-dependent modulo is that `x > %% (2**n)`, where `x` and `n` are integers and `n >= 0`, could always > be safely rewritten to `x & (2**n - 1)` while still preserving > semantics, but `x % (2**n)` does *not* have this property. For > example: > > - `-1 %% (2**1)` → `-1 %% 1` → `1` > - `-1 & (2**1 - 1)` → `-1 & 1` → `1` > - `-1 % (2**1)` → `-1 % 2` → `-1` > > BTW, I literally tested all three of these in Chrome's devtools > console, using my `x %% y` → `(x % y + y) % y` desugaring. > > As for a native implementation and the spec, I'd recommend just doing > `copysign(fmod(x, y), y)` instead to retain precision. > > > At least one disadvantage of an operator over a function, is that you > have to think about precedence. The problem is exacerbated in JS, because > (following some other languages) the unary minus has an uncanny high > precedence level, confusingly very different than the one of the binary > minus; so that, after having designed `**`, it was realised at the last > minute that `-a**b` would be dumbly interpreted as `(-a)**b` instead of > `-(a**b)` or `0-a**b`, as anybody who would be likely to actually use the > operator would expect. (That particular issue was resolved in a hurry by > making the parenthesis-left form a syntax error.) > > I doubt this would happen with `%%`. It's similar enough to the > existing `%` in concept that most would expect it to have the same > precedence. With `**`, there was a very unique issue with it: there > were people actually *reading* it both ways, and even a language > (Python) that interprets `-a ** b` and `-a**b` *differently* in light > of that (as `(-a) ** b` and `-(a ** b)` respectively). That's not a > concern at all with most operators, so it doesn't apply to most new > operator proposals. > > - > > Isiah Meadows > cont...@isiahmeadows.com > www.isiahmeadows.com > On Thu, Aug 15, 2019 at 2:40 AM Claude Pache > wrote: > > > > > > > > Le 12 août 2019 à 22:00, Matthew Morgan a > écrit : > > > > > JS needs a modulo operator. It currently has the remainder operator > `%` which works in most cases except for negative values. I believe the the > `%%` would work great and be easy to remember. > > > > > > let x = (-13) %% 64; > > > is equivalent to > > > let x = ((-13 % 64) + 64) % 64; > > > > > > Is there a strong advantage of an `%%` operator over a `Math.mod()` > function? There is the precedent of the `**` operator implemented as > alternative of `Math.pow()` few years ago. It would be interesting to hear > the feedback of those that use regularly powers, whether the benefit was > clear (personally, I almost never use either `Math.pow()` or `**`, so that > I can’t say anything). > > > > At least one disadvantage of an operator over a function, is that you > have to think about precedence. The problem is exacerbated in JS, because > (following some other languages) the unary minus has an uncanny high > precedence level, confusingly very different than the one of the binary > minus; so that, after having designed `**`, it was realised at the last > minute that `-a**b` would be dumbly interpreted as `(-a)**b` instead of > `-(a**b)` or `0-a**b`, as anybody who would be likely to actually use the > operator would expect. (That particular issue was resolved in a hurry by > making the parenthesis-left form a syntax error.) > > > > —Claude > > > > ___ > > es-discuss mailing list > > es-discuss@mozilla.org > > https://mail.mozilla.org/listinfo/es-discuss > __
Re: Array.prototype.joinWith(iterable)
That;s not useful for template literals tags though _.zip(['a', 'b', 'c'], [1, 2]); [["a", 1], ["b", 2], ["c", undefined]] it basically does nothing I've proposed ... any other name suggestion? On Thu, Aug 15, 2019 at 3:40 PM Michał Wadas wrote: > https://lodash.com/docs/#zip > https://docs.python.org/3/library/functions.html#zip > > On Thu, 15 Aug 2019, 15:34 Andrea Giammarchi, > wrote: > >> >>1. the suggested name is just ... suggested, I don't have strong >>opinion on it, it just `join` values through other values >>2. what's `Array.zip` ? I've no idea >> >> >> On Thu, Aug 15, 2019 at 12:53 PM Michał Wadas >> wrote: >> >>> I would rather see Array.zip, it covers this use case. >>> >>> On Thu, 15 Aug 2019, 10:50 Andrea Giammarchi, < >>> andrea.giammar...@gmail.com> wrote: >>> >>>> >>>> I wonder if there's any interest in adding another handy Array method >>>> as joinWith could be: >>>> >>>> ```js >>>> // proposal example >>>> Array.prototype.joinWith = function (values) { >>>> const {length} = this; >>>> if (length < 2) >>>> return this.join(''); >>>> const out = [this[0]]; >>>> const len = values.length; >>>> for (let i = 1; i < length; i++) { >>>> console.log(i, len); >>>> out.push(values[(i - 1) % len], this[i]); >>>> } >>>> return out.join(''); >>>> }; >>>> ``` >>>> >>>> The goal is to simplify joining array entries through not the same >>>> value, example: >>>> >>>> ```js >>>> console.log(['a', 'b', 'c', 'd'].joinWith([1, 2])); >>>> // a1b2c1d >>>> >>>> function tag2str(template, ...values) { >>>> return template.joinWith(values); >>>> } >>>> >>>> tag2str`a${1}b${2}c`; >>>> // "a1b2c" >>>> ``` >>>> >>>> Throughts? >>>> ___ >>>> es-discuss mailing list >>>> es-discuss@mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Modulo Operator %%
To me there's no risk, as MooTools, Prototype, and Scriptacolous are both things of the past, and never implemented Math.mod ... so, with that approach, custom transpiling functions are more dangerous, as somebody might have implemented `%%` already for other purposes, and we break Babel outcome adding new syntax anyway ... the smoosh accident, is the equivalent of custom Babel utilities these days. Look at TypeScript and the private class fields, if you want to compare new syntax instead On Thu, Aug 15, 2019 at 4:50 PM Michael Haufe wrote: > Thursday, August 15, 2019 2:47 AM, Andrea Giammarchi wrote: > > > > > FWIW another disadvantage is that operators cannot be polyfilled, so > it'll take forever for those not using transpilers to adopt these, while > having a `Math,mod` would work right away > > > > > > With such an approach there is risk of another ‘smooshgate’ [1][2]. There > is nothing stopping those developers from using a function anyway to bridge > the gap if they can’t or won’t use a compiler. This is already the current > state of affairs. > > > > [1] https://developers.google.com/web/updates/2018/03/smooshgate > > [2] > https://adamsilver.io/articles/the-disadvantages-of-javascript-polyfills/ > > > > Michael > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Array.prototype.joinWith(iterable)
1. the suggested name is just ... suggested, I don't have strong opinion on it, it just `join` values through other values 2. what's `Array.zip` ? I've no idea On Thu, Aug 15, 2019 at 12:53 PM Michał Wadas wrote: > I would rather see Array.zip, it covers this use case. > > On Thu, 15 Aug 2019, 10:50 Andrea Giammarchi, > wrote: > >> >> I wonder if there's any interest in adding another handy Array method as >> joinWith could be: >> >> ```js >> // proposal example >> Array.prototype.joinWith = function (values) { >> const {length} = this; >> if (length < 2) >> return this.join(''); >> const out = [this[0]]; >> const len = values.length; >> for (let i = 1; i < length; i++) { >> console.log(i, len); >> out.push(values[(i - 1) % len], this[i]); >> } >> return out.join(''); >> }; >> ``` >> >> The goal is to simplify joining array entries through not the same value, >> example: >> >> ```js >> console.log(['a', 'b', 'c', 'd'].joinWith([1, 2])); >> // a1b2c1d >> >> function tag2str(template, ...values) { >> return template.joinWith(values); >> } >> >> tag2str`a${1}b${2}c`; >> // "a1b2c" >> ``` >> >> Throughts? >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Array.prototype.joinWith(iterable)
I wonder if there's any interest in adding another handy Array method as joinWith could be: ```js // proposal example Array.prototype.joinWith = function (values) { const {length} = this; if (length < 2) return this.join(''); const out = [this[0]]; const len = values.length; for (let i = 1; i < length; i++) { console.log(i, len); out.push(values[(i - 1) % len], this[i]); } return out.join(''); }; ``` The goal is to simplify joining array entries through not the same value, example: ```js console.log(['a', 'b', 'c', 'd'].joinWith([1, 2])); // a1b2c1d function tag2str(template, ...values) { return template.joinWith(values); } tag2str`a${1}b${2}c`; // "a1b2c" ``` Throughts? ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Modulo Operator %%
FWIW another disadvantage is that operators cannot be polyfilled, so it'll take forever for those not using transpilers to adopt these, while having a `Math,mod` would work right away On Thu, Aug 15, 2019 at 8:40 AM Claude Pache wrote: > > > Le 12 août 2019 à 22:00, Matthew Morgan a écrit : > > JS needs a modulo operator. It currently has the remainder operator `%` > which works in most cases except for negative values. I believe the the > `%%` would work great and be easy to remember. > > let x = (-13) %% 64; > is equivalent to > let x = ((-13 % 64) + 64) % 64; > > > Is there a strong advantage of an `%%` operator over a `Math.mod()` > function? There is the precedent of the `**` operator implemented as > alternative of `Math.pow()` few years ago. It would be interesting to hear > the feedback of those that use regularly powers, whether the benefit was > clear (personally, I almost never use either `Math.pow()` or `**`, so that > I can’t say anything). > > At least one disadvantage of an operator over a function, is that you have > to think about precedence. The problem is exacerbated in JS, because > (following some other languages) the unary minus has an uncanny high > precedence level, confusingly very different than the one of the binary > minus; so that, after having designed `**`, it was realised at the last > minute that `-a**b` would be dumbly interpreted as `(-a)**b` instead of > `-(a**b)` or `0-a**b`, as anybody who would be likely to actually use the > operator would expect. (That particular issue was resolved in a hurry by > making the parenthesis-left form a syntax error.) > > —Claude > > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Re: Indexing HTML Attributes and Unique Indexes
> while it could be considered a sub-set, JS is full of HTML related features - `HTMLElement` for one. HTMLElement is defined by the living DOM standard (WHATWG) https://html.spec.whatwg.org/multipage/dom.html#htmlelement it has nothing to do with JS. JS is a general purpose programming language that implements ECMAScript standard, which on the Web gets enriched with some functionality, while on NodeJS it gets enriched with some other (and indeed HTMLELement doesn't exist there). In GJS (Dekstop UI) it has other features too, so asking in a JS related mailing list to bring in something strictly DOM related (whatwg) is not appropriate. Historically speaking, the only thing that went in strictly DOM related where things like String.prototype.blink methods and others, but today JS is *really* not Web based anymore, even if Web is one of its primary goals (but then again, with WASM around, any programming language can target the Web, so you want this proposal to land in WHATWG, not here). Regards On Thu, May 23, 2019 at 7:15 PM Randy Buchholz wrote: > @Andrea Giammarchi , While the connection is > secondary, HTML often serves as the specification for the creation of JS > objects. And while it could be considered a sub-set, JS is full of HTML > related features - `HTMLElement` for one. Thing is, if you are programming > in JS for browser applications, you’re dealing with HTML-adjacent JS at > some point. What I’m trying to do, though, somewhat supports your point. I > see a lot of higher-level code manipulating HTML tags, which feels really > wrong. Even dealing with `HTMLElement` in higher-level code doesn’t seem to > make a lot of sense. I’m trying to encapsulate the elements and tags, and > move that point as far into the background as I can. > > > > @guest271314 > > If we think of Indexes as a type of key-value pairs, a “regular” Index > allows duplicate keys, and a Unique Index requires unique keys. Indexes > are always sorted on their keys. So in this case, when the index is built, > it creates k-v pairs of attributeName-elementId, ordered by attributeName. > To get all elements with a specific attribute, we just find the first one > with that key, and keep reading -`getElementbyId(elementId)` - until the > key changes. > > > > You’re right about `id`. I’m converting generic, multi-instance template > “tags” into elements with id’s, so I can access them directly without > searching. Just using `getElementById`. The template as been “localized” > per instance, and encapsulated behind a controller. I want to avoid dealing > with HTML, and even more HTTP verb related things like `Form` and > `FormData` and just deal with general JS objects, so I use Models instead > of things like `FormData`. > > > > So for example, the business perspective of a ”Person” has “Age” data. A > page may display multiple people at once. > > ``` > > > > > > ``` > > The goal is to get from the source tag to non-html/element related JS as > soon as possible. > > > > The template behind this might look something like > > ``` > > > > > > > > > > ``` > > > > When `connectedCallback` runs, it creates a `View` using the template > > ``` > > > > > > > > > > > > > > > > > > > > ``` > > A `Model` > > ``` > > class person{ > > name; > > age; > > } > > > > And a dynamically configured `Controller` and instance. A base Person > class contains common functionality. > > ``` > > class Person1 extends Person{ > > get name(){ return document.getElementById(‘person1_name’) > > … > > get model(){ return this.populateModel();} > > } > > self.controllers.add(new Person1()); > > ``` > > Now I don’t need to deal with any HTML/element or “tag hierarchy” related > JS. I pretty much abstract out the HTML and HTMLElement pieces when the > Custom Element is initially loaded. > > > > ``` > > const personAge = self.controllers.person1.age; > > ``` > > At a lower level, I can create attribute related properties using the > dynamically assigned element id. > > > > ``` > > > > ``` > > This would end up creating a property or methods on the controller that > allows me to not have to deal with styles and CSS classes directly, and > even constrain values. > > > > ``` > > self.controllers.person1.name.color = “red”; > > ``` > > > > So the whole index thing started when I was loading/parsing dynamic > html/JS code and searching for `prop` and `attrib` repeatedly. If I know > I’m going to be searching on an attribute a lot, maybe I could give the > parser/engine a hint it could use to optimize that search. > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Re: Indexing HTML Attributes and Unique Indexes
it's meant there couldn't be two indexes with the same value, but even IDs can be duplicated on a page (it's not suggested or anything, but nothing prevents you to do that) to be honest, since IDs already cover the whole story (IDs are accessible even via globalThis/window, no need to query the document) I guess this whole story is about having `el.uid`, as opposite of `el.id`, so that a `uid` cannot be duplicated (it throws if it is), and `document.uid[unique-uid-value]` would return, without querying, the live node (if any) however, I think this whole discussion in here makes no sense, as JS itself has nothing to do with HTML 🤷♂️ On Thu, May 23, 2019 at 4:23 PM guest271314 wrote: > If the HTML elements have a unique ```id``` set there is not search to > perform (```document.getElementById("id")```), correct? > > Form fields can be created, set and changed using `FormData` objects > without using HTML elements at all. > > Still not gathering what is meant by unique indexes. > > On Thu, May 23, 2019 at 2:05 PM Randy Buchholz > wrote: > >> Full Table Scans and Unique indexes are database concepts (that's the DBA >> reference). When a database searches for a record based on a column value, >> it might look at every record in the table to find the matches - scan the >> entire (full) table, in the order the records were inserted or stored. To >> speed this up, we can create indexes on table columns or column groups. >> These are like ordered maps or hash tables. To find a record, more >> efficient searches can be done against the indexes to find the records. >> Indexes can also act as constraints. A "Unique Index" is a constraint that >> checks a table to see if a value exists before inserting it in the table >> and adding it to the index. Indexing has a trade-off. It slows inserting, >> but improves searching. While understanding that databases and browsers are >> worlds apart, a foundational part of database engines is searching, just >> like it is in DOM manipulation. Indexing can provide orders of magnitude >> performance improvements when reading/searchin >> g in databases. It seemed worth seeing if the concept translated across >> technologies. >> >> Without any optimizations, an attribute search on a document would look >> at each node, and then at each attribute of the node to find a match - Full >> Table Scan. This makes searches very slow. At an absurd extreme, we could >> index everything, making startup very slow and eating memory, but making >> some searches very fast. The balanced approach is to implement "indexing" >> ourselves (using any of the mentioned approaches) to get the best level. >> >> About the code/HTML, it is dynamic and real-time. It is loaded over >> WebSockets, and the elements are talking to the backend in real-time over >> the sockets. I'm using an original (Trygve Reenskaug) MVC approach. >> Essentially, each Web Component is an MVC component, with the HTML/elements >> and code accessed only through the controller. I am looking at the incoming >> code for cases where several searches ae being performed on the same >> attribute (or element). I give these a generated `id`, create indexes on >> them, and expose them as properties on the controller. The underlying >> framework uses a set of common attributes that are searched on a lot, but >> only for a small set of elements. These are also indexed. So at the cost of >> slower startup (offset to some degree by doing some of this in a Web Worker >> and/or server-side), I can read and write "Form Fields" quickly. >> >> Many language features are implemented to wrap or optimize common or >> repetitive use cases, or to move code to a more efficient part of the >> architecture. Indexing can do both. Without doing things server-side or in >> Workers, the indexing consumes UI cycles. Adding an indexing "hint" could >> allow all or part of this code to be moved back into the "system" or C++ >> layer. (e.g., into `querySelect` internals supported by low-level map >> stores) Or to parsing (like I'm doing), taking some of the repetitive work >> off the UI and developers hands. >> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Indexing HTML Attributes and Unique Indexes
live * On Wed, May 22, 2019 at 7:25 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > With Custom Elements you have `attributeChangedCallback` which reacts > after `observedAttributes` returned attributes, and I believe you'd like to > use that to create getters and setters out of the box. > > I don't think DOM specific class fields/syntax will ever land in JS > itself, but I can suggest you looking at most handy custom elements > patterns in here: > https://gist.github.com/WebReflection/ec9f6687842aa385477c4afca625bbf4 > > About being unique, you can always `document.querySelector('[attribute="' > + value +'"]')` and, if not null, throw an error 'cause already live on the > DOM. > > However, IDs are the most "unique" thing you can have, even if 2 IDs with > same content are still allowed love on the document. > > If you look for an easy way to have unique IDs, remember you can start > from `let id = Math.random()` and do `++id` any other time to have a new, > rarely clashing, unique name. Prefix it with the `nodeName` and see you've > already all uniqueness you need for you custom elements, since you can't > define two custom elements with the same name anyway (yet, unless scoped, > but that's another story). > > Regards > > On Wed, May 22, 2019 at 7:07 PM Randy Buchholz > wrote: > >> I’ve been working with `Custom Elements` and I’m writing a lot of code >> against tag attributes. In some cases, I want the attribute values to be >> unique on a page (like `id`). It got me wondering about how the engines >> handle attribute based searches, and if indexing (with unique/distinct >> options) would provide value. I also find myself writing a lot of >> boilerplate getters/setters for attributes in the elements. Attribute >> handling could be improved by adding some additional support with something >> like an `attrib` feature. This would be similar to `get` or `set` in use. >> >> >> >> ``` >> >> class MyElement extends HTMLElement{ >> >> attrib myAttrib(‘my-attribute’) index distinct; >> >> } >> >> ``` >> >> This would create the attribute `my-attribute` on the tag and element, >> and also generate a getter and setter >> >> ``` >> >> get myAttrib() { return this.getAttribute(‘my-attribute’); } >> >> set myAttrib(v) { this.setAttribute(‘my-attribute’, v); } >> >> ``` >> >> The `index` flag it would tell the engine it should create a map/hash to >> improve search optimization for heavily searched attributes. >> >> The `distinct` flag would indicate that all values for that attribute >> within context (e.g., document) should be unique. This might be used >> primarily by IDE’s to generate warnings. >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Indexing HTML Attributes and Unique Indexes
With Custom Elements you have `attributeChangedCallback` which reacts after `observedAttributes` returned attributes, and I believe you'd like to use that to create getters and setters out of the box. I don't think DOM specific class fields/syntax will ever land in JS itself, but I can suggest you looking at most handy custom elements patterns in here: https://gist.github.com/WebReflection/ec9f6687842aa385477c4afca625bbf4 About being unique, you can always `document.querySelector('[attribute="' + value +'"]')` and, if not null, throw an error 'cause already live on the DOM. However, IDs are the most "unique" thing you can have, even if 2 IDs with same content are still allowed love on the document. If you look for an easy way to have unique IDs, remember you can start from `let id = Math.random()` and do `++id` any other time to have a new, rarely clashing, unique name. Prefix it with the `nodeName` and see you've already all uniqueness you need for you custom elements, since you can't define two custom elements with the same name anyway (yet, unless scoped, but that's another story). Regards On Wed, May 22, 2019 at 7:07 PM Randy Buchholz wrote: > I’ve been working with `Custom Elements` and I’m writing a lot of code > against tag attributes. In some cases, I want the attribute values to be > unique on a page (like `id`). It got me wondering about how the engines > handle attribute based searches, and if indexing (with unique/distinct > options) would provide value. I also find myself writing a lot of > boilerplate getters/setters for attributes in the elements. Attribute > handling could be improved by adding some additional support with something > like an `attrib` feature. This would be similar to `get` or `set` in use. > > > > ``` > > class MyElement extends HTMLElement{ > > attrib myAttrib(‘my-attribute’) index distinct; > > } > > ``` > > This would create the attribute `my-attribute` on the tag and element, and > also generate a getter and setter > > ``` > > get myAttrib() { return this.getAttribute(‘my-attribute’); } > > set myAttrib(v) { this.setAttribute(‘my-attribute’, v); } > > ``` > > The `index` flag it would tell the engine it should create a map/hash to > improve search optimization for heavily searched attributes. > > The `distinct` flag would indicate that all values for that attribute > within context (e.g., document) should be unique. This might be used > primarily by IDE’s to generate warnings. > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Re: Proposal: native XML object support.
People use JSX, which is basically E4X, so I'd argue the word useless is not really appropriate. You can use E4X to produce HTML, the fact we're talking XML is merely about the E4X background, but as you could produce strings out of E4X you could do the same and have better templating out of the box. But like I've said, I already use template literal tags, but those strings don't get hints or highlights as if these were E4X, XML, or plain HTML, which is the only cool thing I'd personally find useful. Maybe it's just a tooling issue though. On Mon, May 20, 2019 at 3:06 PM ViliusCreator wrote: > > the client, it could still somehow shine in NodeJS though. > > > > The only way it can shine is only passing HTML objects as arg to website. > That’s it. And still, you can use string to do that for you. People already > use JSON and I don’t think they would use XML in Node js. There are already > tons of libs for XML stuff, yet they don’t have a lot of downloads, as far > as I remember. > > > > So basically, Node js doesn’t need XML. That would be useless. > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Re: Proposal: native XML object support.
That'd give you info after declaration, which I believe was the major concern in using strings instead of literals. FWIW, I also wish E4X was still a thing, despite these handy and successful template literals based libraries (hyperHTML, lighterhtml, or heresy for the client, viperHTML for NodeJS). However, since `() => ` is always new node while `() => html``` is a unique literal, I think E4X would be a performance nightmare on the client, it could still smehow shine in NodeJS though. Regards On Mon, May 20, 2019 at 2:03 PM ViliusCreator wrote: > > With strings and even E4X, you don't get the same experience that react > supports. Things like property completion in XML mode, XML internal logic, > etc. > > > > Pretty sure you can do this: > > > > ```js > // ... xml function definition > > /** > > * @type {Element} > > * @prop {string} href > > */ > const xmlObj = xml`something` > > ``` > > > This should make editor auto-complete xml object for you. > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Re: Actual WeakSet Use Cases
wickedElements <https://github.com/WebReflection/wicked-elements#wickedelements> is one example: 1. you register CSS selectors used through MutationObserver, so that connected nodes are passed to the 'connected' listener 2. you setup nodes in such listener only if these were not already setup 3. any other disconnect/connect event won't bother nodes setup, if these already handled The disconnected <https://github.com/WebReflection/disconnected#disconnected> utility (used in hyperHTML and lighterhtml): if the node part of the group that has been connected or disconnected was observed, meaning that the WeakSet knew it already, then the event triggers, otherwise nothing happens. In both cases the pattern is pretty similar: const observed = new WeakSet; const observe = node => { observed.add(node); }; const magic = event => { console.log('magic', event.currentTarget); }; const addMagicIfObserved = node => { if (observed.has(node)) node.addListener('magic', magic); for (const child of node.children) addMagicIfObserved(child); }; new MutationObserver(mutations => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { addMagicIfObserved(node); } } }).observe(document, {childList: true, subtree: true}); The list of pros is pretty simple too: 1. with modules scoped utilities, you don't leak undesired details 2. you don't need to cleanup after or change state *unless* you provide a way to stop observing Regards On Tue, Apr 23, 2019 at 9:27 PM Scott Rudiger wrote: > Would anyone mind sharing some examples of the use cases Andrea and Andy > mentioned? > > On Tue, Apr 23, 2019 at 6:32 AM Michał Wadas > wrote: > >> You can't do "branding" by properties on frozen objects. >> >> On Tue, 23 Apr 2019, 13:44 Andy Earnshaw, wrote: >> >>> This is pretty much what I used it for in a previous job role. We loaded >>> and unloaded various iframes, registering APIs and custom elements inside >>> them, adding the `window` object to a WeakSet so the initialisation only >>> ran once. >>> >>> On Tue, 23 Apr 2019 at 10:26, Andrea Giammarchi < >>> andrea.giammar...@gmail.com> wrote: >>> >>>> WeakSet can be very useful in general to avoid *any* object to be >>>> visited/setup twice, not just those coming from user-land classes. >>>> >>>> Circular references, mixins, DOM nodes one-off events handling, and so >>>> on and so fort. >>>> >>>> On Mon, Apr 22, 2019 at 8:26 PM #!/JoePea wrote: >>>> >>>>> (I edited the broken format of my previous post) >>>>> >>>>> What other use cases are there? >>>>> >>>>> On Mon, Apr 22, 2019 at 11:20 AM #!/JoePea wrote: >>>>> >>>>>> > WeakSets are perfect for branding and are how I would expect web >>>>>> platform class branding to be explained. >>>>>> > >>>>>> > ```js >>>>>> > const foos = new WeakSet(); >>>>>> > >>>>>> > class Foo { >>>>>> > constructor() { >>>>>> > foos.add(this); >>>>>> > } >>>>>> > >>>>>> > method() { >>>>>> > if (!foos.has(this)) { >>>>>> > throw new TypeError("Foo.prototype.method called on an >>>>>> incompatible object!"); >>>>>> > } >>>>>> > } >>>>>> > } >>>>>> > ``` >>>>>> >>>>>> Just curious, is that effectively the same as what the (current) >>>>>> [private fields proposal]( >>>>>> https://github.com/tc39/proposal-class-fields) offers? >>>>>> >>>>>> ```js >>>>>> class Foo { >>>>>> #isFoo = true >>>>>> >>>>>> method() { >>>>>> if (this.#isFoo) { >>>>>> throw new TypeError("Foo.prototype.method called on an >>>>>> incompatible object!"); >>>>>> } >>>>>> } >>>>>> } >>>>>> ``` >>>>>> >>>>>> - Joe >>>>>> >>>>> ___ >>>>> es-discuss mailing list >>>>> es-discuss@mozilla.org >>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>> >>>> ___ >>>> es-discuss mailing list >>>> es-discuss@mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Re: Actual WeakSet Use Cases
WeakSet can be very useful in general to avoid *any* object to be visited/setup twice, not just those coming from user-land classes. Circular references, mixins, DOM nodes one-off events handling, and so on and so fort. On Mon, Apr 22, 2019 at 8:26 PM #!/JoePea wrote: > (I edited the broken format of my previous post) > > What other use cases are there? > > On Mon, Apr 22, 2019 at 11:20 AM #!/JoePea wrote: > >> > WeakSets are perfect for branding and are how I would expect web >> platform class branding to be explained. >> > >> > ```js >> > const foos = new WeakSet(); >> > >> > class Foo { >> > constructor() { >> > foos.add(this); >> > } >> > >> > method() { >> > if (!foos.has(this)) { >> > throw new TypeError("Foo.prototype.method called on an >> incompatible object!"); >> > } >> > } >> > } >> > ``` >> >> Just curious, is that effectively the same as what the (current) [private >> fields proposal](https://github.com/tc39/proposal-class-fields) offers? >> >> ```js >> class Foo { >> #isFoo = true >> >> method() { >> if (this.#isFoo) { >> throw new TypeError("Foo.prototype.method called on an incompatible >> object!"); >> } >> } >> } >> ``` >> >> - Joe >> > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: Static Typing
we could add a `Typed` primitive every typed value inherits from, similar way every object implicitly inherits from `Object` these days. That, by contract, would disallow any prototype related operation to either classes or instances, and it will simplify the `Reflect.isTyped(thing)` algo. class MyType extends Typed {} const num:i32 = 123; the `MyType` class, and every instance of it, cannot have mutated prototype, and so cannot the `num`. Typed values will be all shortcuts that behave like a Typed instance. That should solves all cases, right? On Thu, Apr 4, 2019 at 8:52 PM Ranando King wrote: > > if we base any assumption only to the current highly dynamic nature of > JS we won't go too far. > > Problem is that if we infringe on the "current highly dynamic nature of > JS", we'll end up breaking valuable use cases. Any new feature added should > always be 100% compatible with the non-competing portions of the existing > language. > > > I think the mutable prototype issue can be solved through static classes > where no changes would be possible and all instances would be immune to > `setPrototypeOf` > > That solves half of the problem. What of the other half (`Type v = > "somevalue";` where `Type` is not a static class)? With your approach, that > would need to be restricted to solve the other half. Otherwise, you'd still > be facing the issues Waldemar spoke about. > > On Thu, Apr 4, 2019 at 2:49 AM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> If something is missing, let's move forward finding out solutions, 'cause >> if we base any assumption only to the current highly dynamic nature of JS >> we won't go too far. >> >> As example, I think the mutable prototype issue can be solved through >> static classes where no changes would be possible and all instances would >> be immune to `setPrototypeOf` >> >> ``` >> static class MyType {} >> >> Reflect.setPrototypeOf(MyType, Array); // nope >> Reflect.setPrototypeOf(new MyType, []); // nope >> ``` >> >> we'll also need a `Reflect.isTyped(ref)` in case we'd like to throw >> errors on prototype set attempts. >> >> >> >> On Thu, Apr 4, 2019 at 6:11 AM Ranando King wrote: >> >>> > - If you allow user-defined types, objects can spontaneously change >>> their type by mutating their prototype. Thus, you can declare a variable x >>> to have type Foo and check that you're assigning an instance of Foo to it, >>> but the value x can become a Bar (different from a Foo) spontaneously >>> without any operations on x. >>> >>> At least for static typing, the engine will need to freeze a copy of the >>> class definition at the time when the static type is referenced. That >>> frozen type will be associated with the variable in a fixed way, making all >>> attempts to change the type of the variable fail. Also, that would need to >>> divorce the frozen type from the dynamic version so the dynamic version can >>> still be mutated. That concept should work, but it might prove to be >>> ridiculously complicated since it risks a proliferation of objects all of >>> type Foo but with different type definitions. One way to get around that is >>> to flag a type as static the first time it is used in a statically typed >>> variable definition. This would cause an error to be thrown should any part >>> of the class be altered. Not sure how workable that is. >>> >>> > but that begs the question of what is the type of just ['a', 'b']. >>> >>> It should be any[]. Typing should be as non-aggressive as possible. Auto >>> typing should only consider the top level data to determine the type, and >>> in this case, that's an Array. To make c restricted to string elements, the >>> type would need to be specified as string[]. >>> >>> > If you follow this to its logical conclusion and think about what the >>> types of various methods that work on arrays should be, you end up with an >>> enormous and confusing variety of array and object types, which is >>> something we explored years ago. >>> >>> Maybe, but that's always the case with any type system that allows for >>> user-defined types. The main problem here is the memory requirements for >>> storing all of those types. If I remember the description of V8 internals, >>> it seems to have already managed this issue. At least in V8, the challenge >>> would be in permanently associating a specific evolution
Re: Proposal: Static Typing
If something is missing, let's move forward finding out solutions, 'cause if we base any assumption only to the current highly dynamic nature of JS we won't go too far. As example, I think the mutable prototype issue can be solved through static classes where no changes would be possible and all instances would be immune to `setPrototypeOf` ``` static class MyType {} Reflect.setPrototypeOf(MyType, Array); // nope Reflect.setPrototypeOf(new MyType, []); // nope ``` we'll also need a `Reflect.isTyped(ref)` in case we'd like to throw errors on prototype set attempts. On Thu, Apr 4, 2019 at 6:11 AM Ranando King wrote: > > - If you allow user-defined types, objects can spontaneously change > their type by mutating their prototype. Thus, you can declare a variable x > to have type Foo and check that you're assigning an instance of Foo to it, > but the value x can become a Bar (different from a Foo) spontaneously > without any operations on x. > > At least for static typing, the engine will need to freeze a copy of the > class definition at the time when the static type is referenced. That > frozen type will be associated with the variable in a fixed way, making all > attempts to change the type of the variable fail. Also, that would need to > divorce the frozen type from the dynamic version so the dynamic version can > still be mutated. That concept should work, but it might prove to be > ridiculously complicated since it risks a proliferation of objects all of > type Foo but with different type definitions. One way to get around that is > to flag a type as static the first time it is used in a statically typed > variable definition. This would cause an error to be thrown should any part > of the class be altered. Not sure how workable that is. > > > but that begs the question of what is the type of just ['a', 'b']. > > It should be any[]. Typing should be as non-aggressive as possible. Auto > typing should only consider the top level data to determine the type, and > in this case, that's an Array. To make c restricted to string elements, the > type would need to be specified as string[]. > > > If you follow this to its logical conclusion and think about what the > types of various methods that work on arrays should be, you end up with an > enormous and confusing variety of array and object types, which is > something we explored years ago. > > Maybe, but that's always the case with any type system that allows for > user-defined types. The main problem here is the memory requirements for > storing all of those types. If I remember the description of V8 internals, > it seems to have already managed this issue. At least in V8, the challenge > would be in permanently associating a specific evolution of an internal > type to a variable. > > On Wed, Apr 3, 2019 at 7:50 PM Waldemar Horwat > wrote: > >> On 3/23/19 1:34 PM, IdkGoodName Vilius wrote: >> > This is a proposal for static typing. Here is the github repository >> link: https://github.com/CreatorVilius/Proposal-Static-Typing >> > I think it would be great thing in JS. >> >> We intentionally reserved syntax so that something like that would be >> possible in the future. >> >> I've also spent a lot of time working on past proposals to do such >> things. A few interesting issues would invariably arise that make both >> static and runtime typing unsound: >> >> - If you allow user-defined types, objects can spontaneously change their >> type by mutating their prototype. Thus, you can declare a variable x to >> have type Foo and check that you're assigning an instance of Foo to it, but >> the value x can become a Bar (different from a Foo) spontaneously without >> any operations on x. >> >> - Something similar happens with trying to type arrays. You wrote: >> >> let c: auto = ['a', 'b'] // c is now string[] >> >> but that begs the question of what is the type of just ['a', 'b']. >> >> - Is it string[]? No, it can't be that because you can replace its >> second element with a number. >> - Is it any[]? Well, in that case c should have type any[], not string[] >> - Is it object? In that case c should have type Object. >> and so on. >> >> If you follow this to its logical conclusion and think about what the >> types of various methods that work on arrays should be, you end up with an >> enormous and confusing variety of array and object types, which is >> something we explored years ago. In some cases you'd want structural >> types, in some cases you'd want 'like' types (an array of anything which >> just happens to hold numbers at the moment), and so on. >> >> Waldemar >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-dis
Re: Proposal: Static Typing
Actually, on that very same note, since WASM <-> JS might be the only reason, or likely the best one, to have types in JS, let's consider from scratch all WASM types as possible primitives to adopt, shall we? i32 (alias as int?) i64 f32 (alias as float?) f64 u32 (alias uint?) then we have functype (function) limits (dynamic arrays) memory (static arrays) and tables (objects/maps) to deal with, plus global and external. If we find a syntax to represent these types, targeting, or consuming in an optimized way, WASM, might be a reality, with better results than asm.js, since that's very hard to write / remember for humans, IMO. I also would like to know the opinion of someone close to V8 or other engines. Regards On Tue, Mar 26, 2019 at 10:03 AM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > jsdoc doesn't exist in production so it cannot provide any info to the > runtime, making WASM interoperability and hot code optimizations impossible. > > Let's please keep the discussion focused on the achievements current JS > cannot possibly have, thanks. > > > > On Tue, Mar 26, 2019 at 9:06 AM Dan Peddle wrote: > >> It's really a shame few mention jsdoc anymore. It provides mechanisms to >> achieve all of these developer experience quality of life improvements >> without needing transpiling, and on top of standard js of various flavours, >> progressively. >> >> >> On 26. Mar 2019, at 06:43, Ranando King wrote: >> >> Doesn't V8 already use such a concept to manage optimization? When a >> reference's structure mutates, V8 generates a new type by extending the >> previous one with the changes, then kills any affected optimizations around >> the mutated object, forcing re-optimization. Static types would essentially >> provide a guarantee that such re-optimizations would be completely >> unnecessary for the lifetime of the object since it would be impossible to >> mutate the object's structure. It would also allow for early optimization >> since the structure would already be known. These are the benefits of >> static typing. It's not just a matter of developer trust but also engine >> efficiency. >> >> On Tue, Mar 26, 2019 at 12:21 AM Randy Buchholz >> wrote: >> >>> I recently started doing a lot of ES, coming from C# and really missed >>> “typings” at first. But once I learned to think more in es, they became >>> less necessary – even cumbersome in some ways. The question for me on this >>> really comes down to what is a ”type” and what value does it bring. As I >>> see it, a type is a structural contract, in the same way an interface is a >>> behavioral contract. The value of contracts is that they minimize the need >>> to trust. I.e., if I pass a known-type to a function, I can know that it >>> will have a specific structure (e.g., known properties and methods in a >>> class). Without types, I must trust or check the structure. But, types >>> aren’t really self-aware. It is the environment that enforces types. Once >>> you have types, you must have what I call a “Type Authority”. Built-in >>> types are always known by the authority, and when you declare a type, you >>> are adding to what the authority knows. The authority can look at the code >>> and do the “checking” of what is passed based on what it knows. Having >>> types lets me not have to trust in what I am receiving – it can be verified >>> for me. >>> >>> >>> >>> In a compiled language, types provide “hidden” value. The compiler can >>> look at the entire code based and make optimization decisions around types >>> (e.g., in-lining). In a dynamic, interpreted language, (for the most part) >>> this doesn’t happen. Types must be processed at each point of use. So, the >>> value of types stays mostly limited to knowing the structure. Which is >>> though, extremely useful. The problem with static types, is that they exist >>> at the wrong place in time. A static type is a design-time constraint. Yet >>> the environment doesn’t really know about the type until each run-time use. >>> This puts unnecessary limits on the language – adding a property at >>> run-time (while scary at first) is one of my favorite features of the >>> language. Static typing adds other layers of complexity – like namespaces. >>> Locking down a type at design-time essentially “hijacks” a name. A static >>> type “Person” must be consistent across the entire application environment. >>> In uses like Web, where it is common to pull code from many remote sour
Re: Proposal: Static Typing
jsdoc doesn't exist in production so it cannot provide any info to the runtime, making WASM interoperability and hot code optimizations impossible. Let's please keep the discussion focused on the achievements current JS cannot possibly have, thanks. On Tue, Mar 26, 2019 at 9:06 AM Dan Peddle wrote: > It's really a shame few mention jsdoc anymore. It provides mechanisms to > achieve all of these developer experience quality of life improvements > without needing transpiling, and on top of standard js of various flavours, > progressively. > > > On 26. Mar 2019, at 06:43, Ranando King wrote: > > Doesn't V8 already use such a concept to manage optimization? When a > reference's structure mutates, V8 generates a new type by extending the > previous one with the changes, then kills any affected optimizations around > the mutated object, forcing re-optimization. Static types would essentially > provide a guarantee that such re-optimizations would be completely > unnecessary for the lifetime of the object since it would be impossible to > mutate the object's structure. It would also allow for early optimization > since the structure would already be known. These are the benefits of > static typing. It's not just a matter of developer trust but also engine > efficiency. > > On Tue, Mar 26, 2019 at 12:21 AM Randy Buchholz > wrote: > >> I recently started doing a lot of ES, coming from C# and really missed >> “typings” at first. But once I learned to think more in es, they became >> less necessary – even cumbersome in some ways. The question for me on this >> really comes down to what is a ”type” and what value does it bring. As I >> see it, a type is a structural contract, in the same way an interface is a >> behavioral contract. The value of contracts is that they minimize the need >> to trust. I.e., if I pass a known-type to a function, I can know that it >> will have a specific structure (e.g., known properties and methods in a >> class). Without types, I must trust or check the structure. But, types >> aren’t really self-aware. It is the environment that enforces types. Once >> you have types, you must have what I call a “Type Authority”. Built-in >> types are always known by the authority, and when you declare a type, you >> are adding to what the authority knows. The authority can look at the code >> and do the “checking” of what is passed based on what it knows. Having >> types lets me not have to trust in what I am receiving – it can be verified >> for me. >> >> >> >> In a compiled language, types provide “hidden” value. The compiler can >> look at the entire code based and make optimization decisions around types >> (e.g., in-lining). In a dynamic, interpreted language, (for the most part) >> this doesn’t happen. Types must be processed at each point of use. So, the >> value of types stays mostly limited to knowing the structure. Which is >> though, extremely useful. The problem with static types, is that they exist >> at the wrong place in time. A static type is a design-time constraint. Yet >> the environment doesn’t really know about the type until each run-time use. >> This puts unnecessary limits on the language – adding a property at >> run-time (while scary at first) is one of my favorite features of the >> language. Static typing adds other layers of complexity – like namespaces. >> Locking down a type at design-time essentially “hijacks” a name. A static >> type “Person” must be consistent across the entire application environment. >> In uses like Web, where it is common to pull code from many remote sources >> and libraries, how does “Person” remain “static” across these? >> >> >> >> I would propose an alternative to static typing – the Type Authority. The >> Type Authority is a architecture component that (among other things) >> provides “scoped/run-time statics”. Essentially, the Type Authority is an >> application-wide dynamic repository of types, in the run-time environment. >> This opt-in feature would allow dynamically creating types, and then making >> them “fixed” them with application scope. Once registered, the type is >> basically static. Using a hierarchal approach and “dotted” naming notation, >> (e.g., library.component.typename) types can be localized or extended. For >> example, a library can be imported, and types given a “namespace prefix”. >> The qualified name would effectively be a static type within the >> application context. Properties could be dynamically added, and the new >> type registered as a ”child type” (e.g., Person => Person.Domain). This >> would then allow casting - (Person)DomainPersonInstance. A simple Type >> Authority would support basic “is a”/”typeof” capabilities. A more advanced >> system could provide factory methods. >> >> >> >> This approach provides a way to enforce the structural contract nature of >> types, while retaining the dynamic nature of the language. >> ___ >> es-discuss mailing list >
Re: Proposal: Static Typing
* trough (gz) On Mon, Mar 25, 2019 at 11:41 AM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > > WASM interoperability and optimiser efficiency instead of developer > productivity. > > I've personally always seen types useful **only** for typed languages > interoperability and/or optimization/performance hints to engines/runtimes, > but since many developers apparently experience some productivity boost > though typed languages oriented tools, why not having all the three checked? > >- WASM interoperability (a TC39 effort) >- more efficient runtime (a runtime/engine effort) >- boosted productivity (a third parts tools effort) > > That doesn't look too bad to me, as possible JS' future. > > Regards > > > On Mon, Mar 25, 2019 at 11:19 AM Bergi wrote: > >> Hi, >> >> > I am having hard time understanding the counter argument "you need a >> > transpiler anyway". >> >> Sorry, I agree it's a bad argument, I should have just omitted it. >> It was meant to support "If you are only looking for development-time >> benefits, you have to install a static toolchain anyway - which might as >> well transpile away the annotations". >> >> >> the real value of strict types, in my view, is at development time, >> > not at run time. >> > >> > This is not correct. Check what AssemblyScript managed to do via types, >> > targeting WASM instead of non-typed JS >> > >> >> I would be curious to know if anybody has a usage for them at run time >> > >> > Developers might not have such usage, but V8 / Chakra / JSC / >> > SpiderMonkey might spin up optimizations ahead of time, enabling right >> > away hot code. >> >> ...or at least allow throwing exceptions instead of having to >> de-optimise a JITted code, which allows simpler & better optimisation >> algorithms. >> >> These are the kinds of arguments I want to hear, reasons for sending >> type annotations to the client/runtime. And such a goal puts a very >> different focus on what the type system should look like: WASM >> interoperability and optimiser efficiency instead of developer >> productivity. >> >> kind regards, >> Bergi >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: Static Typing
> WASM interoperability and optimiser efficiency instead of developer productivity. I've personally always seen types useful **only** for typed languages interoperability and/or optimization/performance hints to engines/runtimes, but since many developers apparently experience some productivity boost though typed languages oriented tools, why not having all the three checked? - WASM interoperability (a TC39 effort) - more efficient runtime (a runtime/engine effort) - boosted productivity (a third parts tools effort) That doesn't look too bad to me, as possible JS' future. Regards On Mon, Mar 25, 2019 at 11:19 AM Bergi wrote: > Hi, > > > I am having hard time understanding the counter argument "you need a > > transpiler anyway". > > Sorry, I agree it's a bad argument, I should have just omitted it. > It was meant to support "If you are only looking for development-time > benefits, you have to install a static toolchain anyway - which might as > well transpile away the annotations". > > >> the real value of strict types, in my view, is at development time, > > not at run time. > > > > This is not correct. Check what AssemblyScript managed to do via types, > > targeting WASM instead of non-typed JS > > > >> I would be curious to know if anybody has a usage for them at run time > > > > Developers might not have such usage, but V8 / Chakra / JSC / > > SpiderMonkey might spin up optimizations ahead of time, enabling right > > away hot code. > > ...or at least allow throwing exceptions instead of having to > de-optimise a JITted code, which allows simpler & better optimisation > algorithms. > > These are the kinds of arguments I want to hear, reasons for sending > type annotations to the client/runtime. And such a goal puts a very > different focus on what the type system should look like: WASM > interoperability and optimiser efficiency instead of developer > productivity. > > kind regards, > Bergi > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: Static Typing
the day I'll disable autocorrect everywhere will be always too late ... transpolar => transpilers trample => transpile On Mon, Mar 25, 2019 at 10:13 AM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > I am having hard time understanding the counter argument "you need a > transpolar anyway". > > That's been the case since ES2015 landed with breaking syntax that has > been required mandatory transpilation to keep it backward compatible, with > things also not really transpilble such as classes with built-in extends > ability. > > Why suddenly the "need to transpile" is considered a point against any new > JS feature? Are we already done with JS, if that's the case? > > TypeScript exists and it has its own problems, 'cause its slightly > diversions from what's defined via TC39 causes just confusion (i.e. private > fields, to name one, built-in extends still broken if you target ES5, while > Babel 7 fixed that, and template literals behave differently too - Babel 7 > is the only one producing a standard behavior) > > On top of that, many things recently landed in JS has been inspired by > CoffeeScript ... where was the "just use CoffeeScript" argument at that > time? Transpilers were already a thing then too. > > Moreover ... > > > the real value of strict types, in my view, is at development time, not > at run time. > > This is not correct. Check what AssemblyScript managed to do via types, > targeting WASM instead of non-typed JS > > If TypeScript, with its quirks, will be the language that help developers > and win JS in the WASM field, we can start considering JS a second class > citizen of the Web (and soon of the backend too, see deno). > > Is this where we are with JS? > > > I would be curious to know if anybody has a usage for them at run time > > Developers might not have such usage, but V8 / Chackra / JSC / > SpiderMonkey might spin up optimizations ahead of time, enabling right away > hot code. > > > a "toolchain" that allows strict typing using JavaScript without having > to "use TypeScript". > > even if it'll end up being identical or redundant, but I doubt it, for > many companies/teams the least third parts dependencies you have the better > is for code reliability. > > I personally don't trust TS because it breaks when it targets ES5 and I > cannot control what other people target, but I would trust the standard > path and tools aiming at all cost to trample it right, whenever transpiring > is needed. > > With Edge moving to use Chrome, and Firefox and WebKit always catching up, > these days introducing anything new might need transpilers just for a > couple of years, instead of decades. > > Best Regards > > > > > > On Mon, Mar 25, 2019 at 9:55 AM Naveen Chawla > wrote: > >> Yes the real value of strict types, in my view, is at development time, >> not at run time. >> >> However I would be curious to know if anybody has a usage for them at run >> time, and an example of such a case... >> >> Otherwise, yes a "toolchain" that allows strict typing using JavaScript >> without having to "use TypeScript". >> >> On Mon, 25 Mar 2019 at 04:58, Ranando King wrote: >> >>> One thing is definitively true. Any static type system added to ES must >>> not be mandatory. Untyped code must be able to call typed code without >>> forcing references into a fixed type. Likewise, typed code must be able to >>> call untyped code without forcing references to give up type guarantees. >>> >>> On Sun, Mar 24, 2019 at 8:48 PM kai zhu wrote: >>> >>>> i share a similar concern that static-typing makes little sense in >>>> high-churn-rate UX-workflow-programming. >>>> >>>> it encourage people to bikeshed for correctness, on low-level code that >>>> frequently gets rewritten every few weeks/months -- and with often >>>> demoralizing effects. >>>> >>>> > On 24 Mar 2019, at 17:26, Bergi wrote: >>>> > >>>> > Hello, >>>> > to play the devils advocate: why does JavaScript need static typing? >>>> > >>>> > Your proposal doesn't really answer that. Sure, it mentions tooling >>>> and >>>> > IDEs that can provide you with type hints and complain on mistakes, >>>> but >>>> > things like Flow and Typescript do this today already. >>>> > What's your goal, to have JS engines run Typescript(-like) code >>>> natively
Re: Proposal: Static Typing
I am having hard time understanding the counter argument "you need a transpolar anyway". That's been the case since ES2015 landed with breaking syntax that has been required mandatory transpilation to keep it backward compatible, with things also not really transpilble such as classes with built-in extends ability. Why suddenly the "need to transpile" is considered a point against any new JS feature? Are we already done with JS, if that's the case? TypeScript exists and it has its own problems, 'cause its slightly diversions from what's defined via TC39 causes just confusion (i.e. private fields, to name one, built-in extends still broken if you target ES5, while Babel 7 fixed that, and template literals behave differently too - Babel 7 is the only one producing a standard behavior) On top of that, many things recently landed in JS has been inspired by CoffeeScript ... where was the "just use CoffeeScript" argument at that time? Transpilers were already a thing then too. Moreover ... > the real value of strict types, in my view, is at development time, not at run time. This is not correct. Check what AssemblyScript managed to do via types, targeting WASM instead of non-typed JS If TypeScript, with its quirks, will be the language that help developers and win JS in the WASM field, we can start considering JS a second class citizen of the Web (and soon of the backend too, see deno). Is this where we are with JS? > I would be curious to know if anybody has a usage for them at run time Developers might not have such usage, but V8 / Chackra / JSC / SpiderMonkey might spin up optimizations ahead of time, enabling right away hot code. > a "toolchain" that allows strict typing using JavaScript without having to "use TypeScript". even if it'll end up being identical or redundant, but I doubt it, for many companies/teams the least third parts dependencies you have the better is for code reliability. I personally don't trust TS because it breaks when it targets ES5 and I cannot control what other people target, but I would trust the standard path and tools aiming at all cost to trample it right, whenever transpiring is needed. With Edge moving to use Chrome, and Firefox and WebKit always catching up, these days introducing anything new might need transpilers just for a couple of years, instead of decades. Best Regards On Mon, Mar 25, 2019 at 9:55 AM Naveen Chawla wrote: > Yes the real value of strict types, in my view, is at development time, > not at run time. > > However I would be curious to know if anybody has a usage for them at run > time, and an example of such a case... > > Otherwise, yes a "toolchain" that allows strict typing using JavaScript > without having to "use TypeScript". > > On Mon, 25 Mar 2019 at 04:58, Ranando King wrote: > >> One thing is definitively true. Any static type system added to ES must >> not be mandatory. Untyped code must be able to call typed code without >> forcing references into a fixed type. Likewise, typed code must be able to >> call untyped code without forcing references to give up type guarantees. >> >> On Sun, Mar 24, 2019 at 8:48 PM kai zhu wrote: >> >>> i share a similar concern that static-typing makes little sense in >>> high-churn-rate UX-workflow-programming. >>> >>> it encourage people to bikeshed for correctness, on low-level code that >>> frequently gets rewritten every few weeks/months -- and with often >>> demoralizing effects. >>> >>> > On 24 Mar 2019, at 17:26, Bergi wrote: >>> > >>> > Hello, >>> > to play the devils advocate: why does JavaScript need static typing? >>> > >>> > Your proposal doesn't really answer that. Sure, it mentions tooling and >>> > IDEs that can provide you with type hints and complain on mistakes, but >>> > things like Flow and Typescript do this today already. >>> > What's your goal, to have JS engines run Typescript(-like) code >>> natively >>> > without transpiling? For backwards-compatibility you'd have to do that >>> > anyway, especially if new type system features are introduced >>> incrementally. >>> > >>> > What's the point of building this feature into engines? It just >>> provides >>> > additional complexity. Not to mention the difficulty of finding a >>> > suitable type system that is both sophisticated enough to describe all >>> > useful code (not taking away too much flexibility) and simple enough to >>> > understand without a CS degree. And which interfaces well with un-typed >>> > completely dynamic code. >>> > >>> > What does "static typing" even mean to you in a dynamic scripting >>> > language? JavaScript is not compiled by the developer, it is run by the >>> > user. Where (when) do you expect types to be checked? Should the engine >>> > throw early errors (during parsing)? During parsing of which parts of >>> > the code, even when "normal" (untyped) code is calling into typed code? >>> > Or do you expect dynamic runtime errors, like when assigning an invalid >>> > value to a "typed variable"
Re: Proposal: Static Typing
Just my personal thoughts on this. The way PHP migrated to types has been thought incremental steps, and it worked pretty well. Since types have been demanded by the JS community for a while, I think it'd be key to approach JS types not all at once, but through smaller iterations. As example, a proposal with a whole section entitled "Other useless things" would easily diverge focus to stuff the is really not necessary at this point. Since types are also pretty much only a tooling convention, starting just with the most basic need/help, and iterate more complex cases later on, would be probably the best way to go. Reading though all suggestions, I personally think these would be a no brainer to specify and ship as first iteration: - primitives mean primitives (i.e. `string` means `typeof "string"`, no strings attached) - Classes and Built-ins mean classes and built-ins (i.e` String` means any `instanceof String`) - enum could be a new primitive (as in `typeof "enum"`, since static and immutable) but also an expression (like classes), for enums defined as properties/fields of literals and classes - I actually like the `auto` name more than `any`, but without signature overloads/rides the use case would be too broad, so that maybe we should have a way to also define multiple types (i.e. `const notFullyAuto: String|Object|string = value;`) - while I know it's pretty common to have `number[]` as type to define an array of numbers, I also don't understand why a new syntax should have already two different ways to define typed array, i.e. `const list:number[]` and `const list:[number]`, so since the latter one is more powerful/flexible, to define also multiple key/value pairs, maybe that's all we need With these basics, the JS world would already have a huge change. Things we might consider, but me might also don't care about, since these behaviors are part of the specs: - `object` would accept `null`, but since there is no `typeof "null"`, the way to ensure `null` won't be there is to use `Object` instead. Are we OK with that? - `number` would accept `NaN` and `-/Infinity`, but IMO that's the case also without types, if a number is expected. Are we OK with that? - to avoid confusion with binary `|` operations, maybe multiple types could be wrapped in brackets, so that `const index:{number|string}` might look better? That's it for my idea on how this could start moving forward. Best Regards On Sat, Mar 23, 2019 at 9:37 PM IdkGoodName Vilius < viliuskubilius...@gmail.com> wrote: > This is a proposal for static typing. Here is the github repository link: > https://github.com/CreatorVilius/Proposal-Static-Typing > I think it would be great thing in JS. > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Loose idea on "try import"
honestly this look like an `or` would've been great as reserved try import fs from 'fs' or import fs from 'fs-polyfill' or import fs from 'another-fs-polyfill' catch optional, and triggered only if previous 3 imports failed finally optionally do something; On Fri, Mar 1, 2019 at 12:05 PM Michał Wadas wrote: > Syntax: > > try import fs from 'fs' >else import fs from 'fs-polyfill' >else import fs from 'another-fs-polyfill' >else do nothing; // Not sure about syntax > > > try import {watchDirectory} from 'fs' >else import {watchDirectory} from 'fs-polyfill' >else if(process.os === 'ExoticSystem') import {watchDirectory} from > 'another-fs-polyfill' >else throw Error('Your OS doesn\'t support watching directories'); > > Usages: > >- Optional dependencies >- Polyfills > > Problems: > >- This can prevent loading modules before execution if presence of >modules can't be proved statically >- else-if requires execution before loading module - can be dropped > > > I don't have enough time and knowledge about modules to write actual > proposal. > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: `Object.isEmpty(value)`
> 1. If `value` is either `null` or `undefined`, it gracefully falls back to `false` instead of throwing an error. I am having hard time logically thinking of an empty void as false: Object.isEmpty(void 0) is false ? I think keys(o || {}).length === 0 is a more explicit, ambiguity free, alternative. isEmpty(null) === false when typeof null is still object also doesn't feel too right. On Thu, Feb 14, 2019 at 7:31 AM Isiah Meadows wrote: > This would be roughly equivalent to `Object.keys(value).length === 0`, > but with a few exceptions: > > 1. If `value` is either `null` or `undefined`, it gracefully falls > back to `false` instead of throwing an error. > 2. It takes enumerable symbols into account, like `Object.assign`. > > So more accurately, it returns `false` if the value is neither `null` > nor `undefined` and has an own, enumerable property, or `true` > otherwise. > > It's something I sometimes use when dealing with object-based hash > maps (like what you get from JSON, input attributes). I typically fall > back to the (partially incorrect) `for ... in` with a `hasOwnProperty` > check for string keys, but I'd like to see this as a built-in. > > There's also a performance benefit: engines could short-circuit this > for almost everything with almost no type checks. It's also an obvious > candidate to specialize for types. > > - If it's not a reference type (object or function), return `true`. > - If it's not a proxy object, or a proxy object that doesn't define > `getPropertyDescriptor` or `ownKeys`, it's often just a memory load, > even with dictionary objects and arrays. > - If it's a proxy object with `ownKeys` and/or > `getOwnPropertyDescriptor`, this is the slow path, but you can still > short-circuit when `ownKeys` returns an empty array. > > - > > Isiah Meadows > cont...@isiahmeadows.com > www.isiahmeadows.com > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bind function without thisArg
The transpilation is what everyone publishing Web Apps/pages do these days, it's not needed but most developers don't care, they mostly use whatever bundler default is there. The **main** lack of ECMAScript feature is a method that is not based on new syntax, doesn't leak arguments, and transform these into an Array. My proposed `slice.apply(index, arguments)` is still not used by transopilers to solve forever in one place the issue so that production code is full of unnecessary boilerplate every single time some dev uses rest parameters for any callback. If there was a method, not based on new syntax, able to be called through `fn.apply(fn, arguments)` so that arguments wouldn't leak, and transpilers can use a single polyfill as entry point to provide that ability, no extra boilerplate would be ever need in production code. I hope what I've said makes sense 👋 On Mon, Jan 14, 2019 at 4:49 PM Boris Zbarsky wrote: > On 1/14/19 9:47 AM, Andrea Giammarchi wrote: > > rather because of the bloat it produces once transpiled: > > Hold on. > > The transpiling is necessary because of lack of what features in > implementations? > > And what is the set of implementations that will lack those features but > support bindArgs? > > (None of that is an argument against having bindArgs in core per se; I'm > just trying to understand the transpiling issue here.) > > -Boris > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bind function without thisArg
It's not so easy to implement in user land, not because it's difficult to do so: ```js Function.prototype.bindArgs = (...args) => { const fn = this; return function (...moar) { return fn.apply(this, args.concat(moar)); }; }; ``` rather because of the bloat it produces once transpiled: https://bit.ly/2SULtFZ To avoid bloat and `arguments` leaking here and there, one must write something like: ```js function slice() { const arr = []; for (let {length} = arguments, i = +this; i < length; i++) arr.push(arguments[i]); return arr; } Function.prototype.bindArgs = function () { const args = slice.apply(0, arguments); return function () { const moar = slice.apply(0, arguments); return fn.apply(this, args.concat(moar)); }; }; ``` which is still a hell of a boilerplate compared to a native `const ba = fn.bindArgs.apply(fn, arguments);` or `fn.bindArgs(...arguments)` for short. +1 for having this in core On Mon, Jan 14, 2019 at 12:48 PM T.J. Crowder < tj.crow...@farsightsoftware.com> wrote: > Although this is easy enough to implement in userland, frankly so was > `bind`. I'd say it comes up often enough to consider. PrototypeJS (remember > PrototypeJS?) called it `curry`. > > I'd think the specification changes for it would be minimal as well, > basically A) Allowing Empty as boundThis in BoundFunctionCreate and > [[BoundThis]] on functions; B) Updating [[Call]] on Bound Functions to use > thisArgument when boundThis is Empty; creating a new `Function.prototype` > method (`curry` would be the obvious -- and almost certainly **not** > websafe -- name) to call BoundFunctionCreate with Empty for boundThis. > > But I'd be interested to know how difficult it is for JavaScript engines > to implement, since Empty is largely a spec-level concept and it's valid > (in strict mode) to use `null` and `undefined` as boundThis... > > -- T.J. Crowder > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: Add `NoSubstitutionTemplate` to `StringLiteral` Definition
I dare saying tags are another issue here, 'cause "abc" === "abc", and with an identity function such `const id = o => o`, `id("abc") === id("abc")` but due latest changes to template literals, id`abc` !== id`abc` so it's easily misleading in the tagged case. On Wed, Jan 9, 2019 at 7:53 PM Jordan Harband wrote: > import path specifiers are another. > > On Wed, Jan 9, 2019 at 10:16 AM T.J. Crowder < > tj.crow...@farsightsoftware.com> wrote: > >> On Wed, Jan 9, 2019 at 5:36 PM FERREIRA, ERIC B >> wrote: >> > I contend that adding `NoSubstitutionTemplate`s to the definition of >> > `StringLiteral` will bring the benefit of allowing teams to >> > completely opt to use only template strings instead of mixing quote >> > marks, while having very little risk or downside, if any at all. >> >> I've been toying with defaulting to template literals for some time. :-) >> >> Interesting idea. Where specifically do you see benefits of this >> change? The only places that immediately jump out to me are >> >> * "use strict", mentioned in your linked article >> * Quoted property names in object initializers (aka "object literals") >> -- oddly not mentioned in that article (it mentions JSON, but not >> object initializers) >> >> That second one could be a bit of a footgun for people, who may trip >> over this working: >> >> ```js >> const obj = {`I have a space`: `bar`}; >> ``` >> >> ...but this failing: >> >> ```js >> const obj = {`I have a space ${x}`: `bar`}; >> ``` >> >> ...because that's not a NoSubstitutionTemplate and so it needs to be a >> computed property name. >> >> Are there other places? >> >> -- T.J. Crowder >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: Array.prototype.count
[time to write specs, pass through the whole process, ship it to all engines, have it 100% usable without polyfills] [value of this proposal] both sentences represents time, -1 here On Mon, Jan 7, 2019 at 8:35 PM Ranando King wrote: > Either way it goes, there's a lot of ways to do this that are all trivial. > > On Mon, Jan 7, 2019 at 1:31 PM Pier Bover wrote: > >> If you need to find the length of a filtered array IMO it makes more >> sense and is more obvious to just use filter(). >> >> On Mon, Jan 7, 2019 at 1:12 PM Засим Александр >> wrote: >> >>> Hi everyone. This is proposal for Array.prototype.count (or countOf) >>> method which allow to count specific elements in an array. >>> >>> ```js >>> >>> const evenNumberCount = [1, 2, 3, 4, 5].count(num => num % 2 === 0); >>> >>> ``` >>> >>> Instead of >>> >>> ```js >>> >>> const evenNumberCount = [1, 2, 3, 4, 5].filter(num => num % 2 === >>> 0).length; >>> >>> ``` >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: String identity template tag
FWIW, I've used same logic for something like a no-op for i18n`strings` [1] so, considering it has easily use cases with mapped interpolations too, I think it's more than natural to have that in core. It's also backward compatible/polyfillable so this is kinda a no-brainer, name a part, of course. [1] https://github.com/WebReflection/i18n-dummy/blob/master/index.js On Thu, Dec 13, 2018 at 6:15 PM T.J. Crowder < tj.crow...@farsightsoftware.com> wrote: > In general, I think method names should be verbs in the imperative > tense (okay, *mood* if you like linguistic distinctions), which would > argue for `cook` rather than `cooked`. (`String.raw` is an unfortunate > exception to this rule, which has largely been used throughout the > standard library. Another exception is `Reflect.ownKeys`. There are > probably others as well, but they are exceptions, not the norm.) > > I like `cook`. It's `assemble`, but with more flavor. > > The good news here, though, is we're all talking about a name, which > suggests that in general people like the taste of the idea. There > don't seem to be concerns that it's half-baked. > > (I'll stop now.) > > -- T.J. Crowder > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: String identity template tag
I agree with Mark, and I wonder why `String.tag` is not the obvious choice here, since every interpolation is also coerced as String On Thu, Dec 13, 2018 at 9:34 AM Isiah Meadows wrote: > I mean equivalence to untagged behavior, if that helps. > > FWIW, as stated previously, I'm not married to the name. > On Wed, Dec 12, 2018 at 20:31 Mark Miller wrote: > >> >> On Wed, Dec 12, 2018 at 5:24 PM Isiah Meadows >> wrote: >> >>> The template is being expanded as if the template itself is untagged. >> >> >> Does this mean that you describe what tagged templates do, or what >> untagged templates do, as "expanding" something? If so, what is the >> intuition behind that prior usage of "expand"? >> >> >> >>> The point of this is a template tag that just does the default untagged >>> behavior of coercing all expressions to strings and joining the whole thing >>> together. >>> >> >> I certainly agree that the name should suggest equivalence to the default >> untagged behavior. I just never would have thought to describe that >> behavior as "expanding" something. What is it expanded into? >> >> >> >>> On Wed, Dec 12, 2018 at 20:21 Mark Miller wrote: >>> What is the intuition behind "expand"? What is being expanded, and what is it expanding into? On Tue, Dec 11, 2018 at 10:59 PM Isiah Meadows wrote: > Those names a little too generic for my liking here. What about > `String.expand(template, ...params)`? > > And also, let's not try to bake a traditional template engine into the > JS spec - syntactic template strings already work well enough. > > - > > Isiah Meadows > cont...@isiahmeadows.com > www.isiahmeadows.com > > On Wed, Dec 12, 2018 at 1:13 AM Michael Luder-Rosefield > wrote: > > > > Why not String.tag or .tagged? > > > > While we're at it, is there any good reason not to have something > like this: > > > > ``` > > String.template = (template : String, > taggerFn=String.identity/tag/tagged : Function) => (keys : Array | Object) > => taggerFn(template, (keys is Array) ? ...keys : keys) > > // apologies for pseudo-semi-functional code > > // having keys be an object allows template to be filled by key name > rather than just index > > ``` > > This would make templates closer to the traditional usage, where the > template comes first and is later passed values to be filled in with. > Having the taggerFn as an argument allows for things like Isiah's > escape-then-apply tagging examples. > > > > > > On Wed, 12 Dec 2018 at 12:51 Isiah Meadows > wrote: > >> > >> I'm not married to `identity`, and I agree the name is probably not > >> ideal. I'm more concerned about functionality, though. > >> > >> - > >> > >> Isiah Meadows > >> cont...@isiahmeadows.com > >> www.isiahmeadows.com > >> > >> On Tue, Dec 11, 2018 at 5:41 AM T.J. Crowder > >> wrote: > >> > > >> > On Mon, Dec 10, 2018 at 7:08 PM Isiah Meadows > >> > wrote: > >> > > > >> > > It'd be *way* easier to construct simple template tags if there > was a > >> > > built-in identity tag > >> > > >> > Wholeheartedly agree, a couple of months ago I considered posting > something very similar, both for utility reasons and in hopes that it > would > be an optimization target (being a standard operation). > >> > > >> > I find the name `identity` unilluminating, though, partially > because it's not quite the same meaning as the usual "identity" function > (`function identity(x) { return x; }`), though it's close. `assemble`? > >> > > >> > -- T.J. Crowder > >> ___ > >> es-discuss mailing list > >> es-discuss@mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -- Cheers, --MarkM >>> >> >> -- >> Cheers, >> --MarkM >> > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
I don't think introducing `public` here has any value. We have `static #a = 1` eventually for private already, the default should follow the classes behavior, IMO On Wed, Dec 5, 2018 at 10:46 PM Ranando King wrote: > That's the kind of thing I was shooting for with static lexical scope > variables. There's 2 problems with it given the way things are going > though. Take a look. > > ```js > function foo() { > static a=1, > b=2, > c=3; > } > ``` > By the way I'm thinking, this would create 3 static variables within foo > that are only initialized once and retain whatever value is set on them > across invocations. Basically, the object `foo` carries around a closure > containing those values. Problem is, this is private to foo. That conflicts > with class-fields and it's sigil-means-private model. > > Ignoring that, public static variables can also be done (but it'd be the > first ever introduction of `public` in ES. > ```js > function foo() { > static public a=1, > b=2, > c=3; > } > ``` > This would make `foo.a`, `foo.b`, & `foo.c` accessible as public > properties of `foo`. > > Think this needs to be a proposal? > > > On Wed, Dec 5, 2018 at 1:39 AM Isiah Meadows > wrote: > >> Personally, I'd prefer something else: a means of a function object >> literal that's still callable, but I can tack other properties to it >> easily. Something like this, maybe: >> >> ```js >> { >> (...args) { ... }, >> } >> ``` >> >> In this, the `this` value is set to the callee itself, not the given >> `this` value. >> >> Not married to the syntax, but I want the functionality. >> On Wed, Dec 5, 2018 at 01:34 Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> > the apply hook needs objects anyway. >>> >>> I meant functions >>> >>> On Wed, Dec 5, 2018 at 1:33 PM Andrea Giammarchi < >>> andrea.giammar...@gmail.com> wrote: >>> >>>> I've actually replied to the op, I didn't mean to answer you directly, >>>> but the only reason I wrote that is because I could, no other reasons. >>>> >>>> However, people unaware of the handleEvent pattern for event listeners >>>> often hope to be able to pass objects as listeners, ignoring the fact they >>>> can do that already (but they need a handleEvent method, own or inherited, >>>> in that object). >>>> >>>> There is at least another use case I can't remember now, but I do >>>> remember doing the Proxy dance before ending up realizing that the apply >>>> hook needs objects anyway. >>>> >>>> But yeah, I don't think it's a must have, specially because we can have >>>> something similar already, as shown in my example. >>>> >>>> >>>> On Wed, Dec 5, 2018 at 1:25 PM Ranando King wrote: >>>> >>>>> Maybe I asked it wrong. >>>>> >>>>> How is making an ordinary object callable at all useful for anything >>>>> that can't already be easily handled via objects and functions? (looking >>>>> for use cases here) >>>>> How does this make coding easier to do and understand? (for the AST >>>>> parser and for the human) >>>>> >>>>> On Tue, Dec 4, 2018 at 11:54 PM Andrea Giammarchi < >>>>> andrea.giammar...@gmail.com> wrote: >>>>> >>>>>> How about this: >>>>>> >>>>>> ```js >>>>>> >>>>>> // the poly >>>>>> if (!Symbol.callable) >>>>>> Symbol.callable = Symbol('callable'); >>>>>> >>>>>> // the setup >>>>>> class Callable extends Function { >>>>>> constructor(object) { >>>>>> super('return arguments.callee[Symbol.callable](...arguments)'); >>>>>> //sloppy mode FTW! >>>>>> Object.setPrototypeOf(this, object); >>>>>> } >>>>>> } >>>>>> >>>>>> >>>>>> // the example >>>>>> const obj = new Callable({ >>>>>> [Symbol.callable](value) { >>>>>> return value + this.value; >>>>>> }, >>>>>> value: 123 >>>>>> }); >>>>>> >>>>>> obj(7); // 130 >>>>>> >>>>>> >>>>>> ``` >>>>>> >>>>>> On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: >>>>>> >>>>>>> Something along the lines of Symbol.iterator protocol for defining >>>>>>> callback objects i.e: Symbol.callable: >>>>>>> >>>>>>> const obj = { >>>>>>> [Symbol.callable]: function (...args) { return >>>>>>> this[Symbol.for('value')] }, >>>>>>> [Symbol.for(''value')]: 'value', >>>>>>> } >>>>>>> >>>>>>> assert(obj() === 'value') >>>>>>> ___ >>>>>>> es-discuss mailing list >>>>>>> es-discuss@mozilla.org >>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>> >>>>>> ___ >>>>>> es-discuss mailing list >>>>>> es-discuss@mozilla.org >>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>> >>>>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
> the apply hook needs objects anyway. I meant functions On Wed, Dec 5, 2018 at 1:33 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > I've actually replied to the op, I didn't mean to answer you directly, but > the only reason I wrote that is because I could, no other reasons. > > However, people unaware of the handleEvent pattern for event listeners > often hope to be able to pass objects as listeners, ignoring the fact they > can do that already (but they need a handleEvent method, own or inherited, > in that object). > > There is at least another use case I can't remember now, but I do remember > doing the Proxy dance before ending up realizing that the apply hook needs > objects anyway. > > But yeah, I don't think it's a must have, specially because we can have > something similar already, as shown in my example. > > > On Wed, Dec 5, 2018 at 1:25 PM Ranando King wrote: > >> Maybe I asked it wrong. >> >> How is making an ordinary object callable at all useful for anything that >> can't already be easily handled via objects and functions? (looking for use >> cases here) >> How does this make coding easier to do and understand? (for the AST >> parser and for the human) >> >> On Tue, Dec 4, 2018 at 11:54 PM Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> How about this: >>> >>> ```js >>> >>> // the poly >>> if (!Symbol.callable) >>> Symbol.callable = Symbol('callable'); >>> >>> // the setup >>> class Callable extends Function { >>> constructor(object) { >>> super('return arguments.callee[Symbol.callable](...arguments)'); >>> //sloppy mode FTW! >>> Object.setPrototypeOf(this, object); >>> } >>> } >>> >>> >>> // the example >>> const obj = new Callable({ >>> [Symbol.callable](value) { >>> return value + this.value; >>> }, >>> value: 123 >>> }); >>> >>> obj(7); // 130 >>> >>> >>> ``` >>> >>> On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: >>> >>>> Something along the lines of Symbol.iterator protocol for defining >>>> callback objects i.e: Symbol.callable: >>>> >>>> const obj = { >>>> [Symbol.callable]: function (...args) { return >>>> this[Symbol.for('value')] }, >>>> [Symbol.for(''value')]: 'value', >>>> } >>>> >>>> assert(obj() === 'value') >>>> ___ >>>> es-discuss mailing list >>>> es-discuss@mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
I've actually replied to the op, I didn't mean to answer you directly, but the only reason I wrote that is because I could, no other reasons. However, people unaware of the handleEvent pattern for event listeners often hope to be able to pass objects as listeners, ignoring the fact they can do that already (but they need a handleEvent method, own or inherited, in that object). There is at least another use case I can't remember now, but I do remember doing the Proxy dance before ending up realizing that the apply hook needs objects anyway. But yeah, I don't think it's a must have, specially because we can have something similar already, as shown in my example. On Wed, Dec 5, 2018 at 1:25 PM Ranando King wrote: > Maybe I asked it wrong. > > How is making an ordinary object callable at all useful for anything that > can't already be easily handled via objects and functions? (looking for use > cases here) > How does this make coding easier to do and understand? (for the AST parser > and for the human) > > On Tue, Dec 4, 2018 at 11:54 PM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> How about this: >> >> ```js >> >> // the poly >> if (!Symbol.callable) >> Symbol.callable = Symbol('callable'); >> >> // the setup >> class Callable extends Function { >> constructor(object) { >> super('return arguments.callee[Symbol.callable](...arguments)'); >> //sloppy mode FTW! >> Object.setPrototypeOf(this, object); >> } >> } >> >> >> // the example >> const obj = new Callable({ >> [Symbol.callable](value) { >> return value + this.value; >> }, >> value: 123 >> }); >> >> obj(7); // 130 >> >> >> ``` >> >> On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: >> >>> Something along the lines of Symbol.iterator protocol for defining >>> callback objects i.e: Symbol.callable: >>> >>> const obj = { >>> [Symbol.callable]: function (...args) { return >>> this[Symbol.for('value')] }, >>> [Symbol.for(''value')]: 'value', >>> } >>> >>> assert(obj() === 'value') >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
How about this: ```js // the poly if (!Symbol.callable) Symbol.callable = Symbol('callable'); // the setup class Callable extends Function { constructor(object) { super('return arguments.callee[Symbol.callable](...arguments)'); //sloppy mode FTW! Object.setPrototypeOf(this, object); } } // the example const obj = new Callable({ [Symbol.callable](value) { return value + this.value; }, value: 123 }); obj(7); // 130 ``` On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: > Something along the lines of Symbol.iterator protocol for defining > callback objects i.e: Symbol.callable: > > const obj = { > [Symbol.callable]: function (...args) { return > this[Symbol.for('value')] }, > [Symbol.for(''value')]: 'value', > } > > assert(obj() === 'value') > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: What is holding back Decorators ?
Btw, I don't care 'cause I find the inline syntax to export a class ugly in either ways so I hope that is not a blocker 'cause I don't see it a real blocker in the real world, while not having decorators is a real issue in the real world. Thanks for moving forward. Best Regards On Wed, Dec 5, 2018 at 7:44 AM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > It's well known that twitter users pay a lot of attention to details, vote > only once they've understood the issue and their own opinions about > technical matters, and follow closer this channel since ever ... > > > > On Wed, Dec 5, 2018 at 2:18 AM T.J. Crowder < > tj.crow...@farsightsoftware.com> wrote: > >> On Tue, Dec 4, 2018 at 7:08 PM T.J. Crowder >> wrote: >> > >> > I believe there already is one: >> > https://github.com/tc39/proposal-decorators/issues/69 >> >> Apparently there was a poll (**really** wish someone had mentioned it >> here, following ALL contributors to proposals on twitter is not >> scalable): >> https://twitter.com/littledan/status/1050815837962158080 >> >> The @dec export got 36% vs. export @dec at 22 with 29% saying they >> don't care which. >> >> -- T.J. Crowder >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss