[Proposal] New syntax for lazy getters

Isiah Meadows isiahmeadows at gmail.com
Wed Jun 27 13:10:41 UTC 2018


If you're wanting to propose new places for decorators, you'd have much
better luck here: https://github.com/tc39/proposal-decorators

I do agree this is an obvious place for a decorator, and it is probably the
ideal way of specifying it for object properties, but your larger proposal
of adding decorators for objects would have better luck there.

-----

Isiah Meadows
me at isiahmeadows.com
www.isiahmeadows.com

On Wed, Jun 27, 2018 at 8:23 AM, kai zhu <kaizhu256 at gmail.com> wrote:

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


More information about the es-discuss mailing list