<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><blockquote type="cite" class=""><div dir="ltr" class=""><div class="">What it's doesn't cover (and in my opinion should be the focus of a new proposal) is Decorators for literal objects. Something like the code below is yet not proposed:</div><div class=""><br class="">``` js</div><div class="">const foo = {</div><div class="">  @lazy bar: 3,</div><div class="">};<br class="">```</div></div></blockquote><div class=""><br class=""></div><div class="">what would happen if you tried to JSON.stringify foo? a core-value of javascript to industry is as an idiot-proof/least-surprise language for serializing json-data across browser <-> server.  junior-programmers who naively employ hard-to-serialize things like custom-getters in their low-level code, mostly end up annoying senior-programmers when they have to debug high-level integration-code that have problems baton-passing those states around.</div><br class=""><div class="">
<div style="color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;">kai zhu</div><div style="color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><a href="mailto:kaizhu256@gmail.com" class="">kaizhu256@gmail.com</a></div><div style="color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><br class="Apple-interchange-newline">
</div>
<br class=""><div><blockquote type="cite" class=""><div class="">On 12 Jun 2018, at 9:07 PM, Isiah Meadows <<a href="mailto:isiahmeadows@gmail.com" class="">isiahmeadows@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">BTW, I proposed similar (lazy values) 9 months ago [1], and it's been<br class="">on the list plenty of times [2]. I'd personally *love* to see it<br class="">happen, but I find it not very likely it'd make it, especially as a<br class="">property (since decorators can rectify that).<br class=""><br class="">[1]: <a href="https://esdiscuss.org/topic/lazy-evaluation" class="">https://esdiscuss.org/topic/lazy-evaluation</a><br class="">[2]: <a href="https://www.google.com/search?q=site%3Aesdiscuss.org+lazy+property+OR+getter+OR+setter" class="">https://www.google.com/search?q=site%3Aesdiscuss.org+lazy+property+OR+getter+OR+setter</a><br class=""><br class="">-----<br class=""><br class="">Isiah Meadows<br class=""><a href="mailto:me@isiahmeadows.com" class="">me@isiahmeadows.com</a><br class="">www.isiahmeadows.com<br class=""><br class=""><br class="">On Tue, Jun 12, 2018 at 8:48 AM, Andrea Giammarchi<br class=""><andrea.giammarchi@gmail.com> wrote:<br class=""><blockquote type="cite" class="">FWIW, I think to keep it simple `lazy: true` would be enough for the time<br class="">being.<br class=""><br class="">Having the new descriptor inside the descriptor seems a bit over engineering<br class="">at this point, imo, but having a field already won't exclude, in the<br class="">feature, the ability to improve that field (similar way addEventListener on<br class="">DOM got promoted from `(type, handler, boolean)` signature to `(type,<br class="">handler, boolean || options)`)<br class=""><br class="">I also agree that `lazy field = expr` is a different beast, and it won't<br class="">play well with descriptors as we know, but it might allow overwrites if<br class="">accessed directly.<br class=""><br class="">I wouldn't mind that as long as it plays well with objects and classes, and<br class="">as long as there is an official way to lazy define properties, and if it<br class="">could be so lazy that if redefined disappears, in that direct assignment<br class="">form, it would be a solution to all my cases.<br class=""><br class="">Regards<br class=""><br class=""><br class="">On Tue, Jun 12, 2018 at 2:37 PM, <herby@mailbox.sk> wrote:<br class=""><blockquote type="cite" class=""><br class="">Actually, by malleable I meant only configurable:true, so one can change<br class="">it via Object.defineProp… api, I did not mean necessarily to define it as<br class="">value.<br class=""><br class="">I have no strong opinion on what should be there after the first access,<br class="">but it boils down on how will it be exposed via Object.defineProperty,<br class="">really, because as little as possible should be changed, IOW as much as<br class="">possible retained.<br class=""><br class="">So on case things are defined as (only pondering the property descriptor<br class="">here, the call is obvious):<br class=""><br class="">  { lazy: true, get: () => Math.random() } … [1]<br class=""><br class="">or, bigger example:<br class=""><br class="">  { lazy: { configurable: false }, enumerable: false, get: () =><br class="">foos.length, set: x => console.log(`set ${x}`) } … [2]<br class=""><br class="">Then what should be generated is indeed a getter so that setter may be<br class="">retained as well in [2].<br class=""><br class="">If the definition is:<br class=""><br class="">{ lazy: { configurable: false, writable: false, enumerable: true, compute:<br class="">() => Math.random() }, enumerable: false } … [3]<br class=""><br class="">then it defines a value (which is not enumerable until first accessed thus<br class="">created; contrived example, I know).<br class=""><br class="">This post also shows a proposal how to, in future proof way, define what<br class="">attributes will the replaced getter/value have: put it In lazy field of prop<br class="">descriptor, lazy: true means shortcut for “the default way / Inherit from<br class="">what is there now”.<br class=""><br class="">Herby<br class=""><br class="">On June 12, 2018 2:02:28 PM GMT+02:00, Aadit M Shah<br class=""><aaditmshah@fastmail.fm> wrote:<br class=""><blockquote type="cite" class="">Okay, so my previous statement about field declarations in classes<br class="">being<br class="">invalid was incorrect. I didn't see Andrea's link to the class field<br class="">declarations proposal[1]. Hence, from what I understand we're<br class="">considering the following syntax:<br class="">const zeros = { head: , lazy tail: this };<br class=""><br class="">class Random {<br class="">   lazy value = Math.random();<br class="">}<br class=""><br class="">As for semantics, Herby's philosophy of "malleable unless specified<br class="">otherwise" makes sense. Hence, the above code would be transpiled to:<br class="">const zeros = {<br class="">   head: ,<br class="">   get tail() {<br class="">       return Object.defineProperty(this, "tail", {<br class="">           value: this<br class="">       }).tail;<br class="">   }<br class="">};<br class=""><br class="">class Random {<br class="">   get value() {<br class="">       return Object.defineProperty(this, "value", {<br class="">           value: Math.random()<br class="">       }).value;<br class="">   }<br class="">}<br class=""><br class="">I guess we'd also be adopting the syntax for private fields and static<br class="">fields? For example, lazy #value and lazy static #value?<br class=""><br class="">On Tue, Jun 12, 2018, at 7:32 AM, herby@mailbox.sk wrote:<br class=""><blockquote type="cite" class=""><br class=""><br class="">On June 12, 2018 11:32:22 AM GMT+02:00, Aadit M Shah<br class=""><aaditmshah@fastmail.fm> wrote:>> Actually, from a parsing<br class=""></blockquote>perspective I believe it shouldn't be too<br class=""><blockquote type="cite" class=""><blockquote type="cite" class="">difficult to implement the `lazy name: expression` syntax. In<br class="">addition, I'm not too keen on your `lazy name() { return<br class=""></blockquote></blockquote>expression;>> }` syntax because:<br class=""><blockquote type="cite" class=""><blockquote type="cite" class="">1. It's more verbose.<br class="">2. It seems to me that it's no different than creating a regular<br class="">  getter:<br class=""><br class="">const take = (n, xs) => n ===  ? null : xs && {    head: xs.head,<br class="">get<br class="">tail() {        const value = take(n - 1, xs.tail);<br class="">Object.defineProperty(this, "tail", {            configurable:<br class=""></blockquote></blockquote>false,>> get: () => value        });        return value;    } };<br class=""><blockquote type="cite" class=""><br class="">I am pretty sure Andrea mixed syntax of lazy getter with its<br class="">implementation for brevity, and the actual lazy getter would<br class="">look like:><br class="">  lazy tail() { return take(n - 1, xs.tail); }<br class=""><br class=""><blockquote type="cite" class="">Regarding the second bullet point, I've probably misunderstood<br class="">what you>> were trying to convey. Perhaps you could elucidate.<br class="">Anyway, making the property non-configurable after accessing it<br class=""></blockquote></blockquote>seems>> like a reasonable thing to do.<br class=""><blockquote type="cite" class=""><br class="">Here I disagree. No syntax construct so far forces immutability. The<br class="">get x() / set x() ones are configurable. If you defined lazy getter<br class="">so far by get(), you could have changed it using<br class="">Object.defineProperties if there was some strange need for it. You<br class="">had to explicitly freeze etc. or defineProperty with configurable<br class="">false if you wanted to make it so.><br class="">This autofreezing if the value sticks out out this philosophy of "<br class="">malleable unless specified otherwise".><br class=""><blockquote type="cite" class=""><br class="">On Tue, Jun 12, 2018, at 3:44 AM, Andrea Giammarchi wrote:<br class=""><blockquote type="cite" class="">My 2 cents,<br class="">I use lazy getters since about ever and I'd love to have such<br class=""></blockquote>syntax<br class=""><blockquote type="cite" class="">in place but I think there is room for some improvement /<br class="">simplification in terms of syntax.><br class="">*## Keep it get*ish**<br class=""><br class="">From parsing perspective, introducing `lazy tail()` seems way<br class="">simpler>>> than introducing `lazy tail:` for the simple reason that<br class=""></blockquote></blockquote></blockquote>everything>>> that can parse `get tail()` and `set tail()` is in place<br class="">already in>>> every engine. I don't write them but I'm sure having an<br class="">extra<br class=""><blockquote type="cite" class=""><blockquote type="cite" class="">keyboard<br class=""><blockquote type="cite" class="">to catch shouldn't be crazy complicated.><br class="">*## class compatible*<br class=""><br class="">because you used `delete this.tail` and mentioned functional<br class="">programming, I'd like to underline ES doesn't force anyone to one<br class="">programming style or another. That means new syntax should play<br class=""></blockquote>nicely<br class=""><blockquote type="cite" class="">with classes too, and in this case the proposal doesn't seem to<br class="">address that because of the direct value mutation, as generic<br class="">property, and the removal of that property from the object,<br class="">something>>> not needed if inherited.><br class="">My variant would do the same, except it would keep the value an<br class="">accessor:><br class="">```js<br class="">const take = (n, xs) => n === 0 ? null : xs && {<br class="">  head: xs.head,<br class="">  lazy tail() {<br class="">    return Object.defineProperty(this, 'tail', {<br class="">      configurable: false,<br class="">      get: (value =><br class="">        // still a getter<br class="">        () => value<br class="">      )(<br class="">        // executed once<br class="">        take(n - 1, xs.tail)<br class="">      )<br class="">    }).tail;<br class="">  }<br class="">};<br class="">```<br class=""><br class="">This would keep initial accessor configuration, in terms of<br class="">enumerability, but it will freeze its value forever and, on top of<br class="">that, this will play already well with current valid ES2015<br class="">classes syntax.><br class="">I also believe myself proposed something similar a while ago (or<br class="">somebody else and I agreed with that proposal) but for some<br class="">reason it>>> never landed.><br class="">Hopefully this time the outcome would be different.<br class=""><br class="">Best Regards<br class=""><br class=""><br class=""><br class=""><br class="">On Tue, Jun 12, 2018 at 9:13 AM, Aadit M Shah<br class=""><aaditmshah@fastmail.fm> wrote:>> __<br class=""><blockquote type="cite" class="">Hello TC39,<br class=""><br class="">I recently opened an issue[1] in the tc39/ecma262[2] repository,<br class="">proposing a new syntax for lazy getters, and I was directed to<br class=""></blockquote></blockquote></blockquote></blockquote>the>>>> CONTRIBUTING[3] page which stated that I should start a<br class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class="">conversation>>>> on this mailing list.>><br class="">So, my feature proposal is to have syntactic sugar for<br class="">creating lazy>>>> getters[4]. To summarize my original proposal<br class=""></blockquote></blockquote></blockquote></blockquote>(which you can<br class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class="">read by>>>> following the very first link above), I find that<br class=""></blockquote></blockquote></blockquote></blockquote>creating lazy<br class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class="">getters is very verbose. For example, consider:>><br class="">const take = (n, xs) => n ===  ? null : xs && {<br class="">  head: xs.head,<br class="">  get tail() {<br class="">      delete this.tail;<br class="">      return this.tail = take(n - 1, xs.tail);<br class="">  }<br class="">};<br class=""><br class="">My proposed solution is to add a new keyword lazy to the<br class=""></blockquote></blockquote></blockquote></blockquote>language.>>>> This keyword can only be used as a prefix to longhand<br class="">property<br class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class="">names>>>> in object initializers, and it defers the execution of<br class=""></blockquote></blockquote></blockquote></blockquote>the value<br class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class="">expression until the property is accessed. In short, it's just<br class="">syntactic sugar for lazy getters:>><br class="">const take = (n, xs) => n ===  ? null : xs && {<br class="">  head: xs.head,<br class="">  lazy tail: take(n - 1, xs.tail)<br class="">};<br class=""><br class="">This is purely syntactic sugar. The semantics of this new syntax<br class="">would remain the same as that of the desugared syntax. In<br class=""></blockquote></blockquote>particular,<br class=""><blockquote type="cite" class=""><blockquote type="cite" class="">calling Object.getOwnPropertyDescriptor(list, "tail") would<br class=""></blockquote></blockquote></blockquote></blockquote>return>> an<br class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class="">accessor descriptor before accessing list.tail and a data<br class="">descriptor>>>> afterwards.>><br class="">Furthermore, there are other advantages of having this syntactic<br class="">sugar. For example, creating cyclic data structures becomes much<br class="">easier. Examples are provided in my original proposal which is<br class=""></blockquote></blockquote>linked<br class=""><blockquote type="cite" class=""><blockquote type="cite" class="">above. Hope to hear your thoughts on this.>><br class="">Regards,<br class="">Aadit M Shah<br class=""><br class="">_________________________________________________<br class="">es-discuss mailing list<br class="">es-discuss@mozilla.org<br class="">https://mail.mozilla.org/listinfo/es-discuss<br class=""><br class=""></blockquote></blockquote><br class=""><br class="">Links:<br class=""><br class="">1. https://github.com/tc39/ecma262/issues/1223<br class="">2. https://github.com/tc39/ecma262<br class="">3. https://github.com/tc39/ecma262/blob/master/CONTRIBUTING.md<br class="">4.<br class=""><br class=""></blockquote></blockquote></blockquote><br class=""><blockquote type="cite" class=""><blockquote type="cite" class="">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#Smart_self-overwriting_lazy_getters<br class=""></blockquote><br class="">Links:<br class=""><br class=""> 1. https://github.com/tc39/proposal-class-fields#field-declarations<br class=""></blockquote></blockquote><br class=""><br class=""><br class="">_______________________________________________<br class="">es-discuss mailing list<br class="">es-discuss@mozilla.org<br class="">https://mail.mozilla.org/listinfo/es-discuss<br class=""><br class=""></blockquote>_______________________________________________<br class="">es-discuss mailing list<br class="">es-discuss@mozilla.org<br class="">https://mail.mozilla.org/listinfo/es-discuss<br class=""></div></div></blockquote></div><br class=""></body></html>