[Proposal] New syntax for lazy getters

classic Classic list List threaded Threaded
26 messages Options
12
Reply | Threaded
Open this post in threaded view
|

[Proposal] New syntax for lazy getters

Aadit M Shah
Hello TC39,

I recently opened an issue in the tc39/ecma262 repository, proposing a new syntax for lazy getters, and I was directed to the CONTRIBUTING 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. 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 === 0 ? 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 === 0 ? 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Jordan Harband
How would this work when the getter lives on a prototype? (like most builtin getters) Would it install the memoized value on `this`, or on the object that contains the getter? Would it use [[Set]] or [[Define]]?

On Tue, Jun 12, 2018 at 12:13 AM, Aadit M Shah <[hidden email]> wrote:
Hello TC39,

I recently opened an issue in the tc39/ecma262 repository, proposing a new syntax for lazy getters, and I was directed to the CONTRIBUTING 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. 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 === 0 ? 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 === 0 ? 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Andrea Giammarchi-2
In reply to this post by Aadit M Shah
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 getish

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 <[hidden email]> wrote:
Hello TC39,

I recently opened an issue in the tc39/ecma262 repository, proposing a new syntax for lazy getters, and I was directed to the CONTRIBUTING 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. 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 === 0 ? 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 === 0 ? 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Andrea Giammarchi-2
having an extra keyword ...

On Tue, Jun 12, 2018 at 9:44 AM, Andrea Giammarchi <[hidden email]> 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 getish

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 <[hidden email]> wrote:
Hello TC39,

I recently opened an issue in the tc39/ecma262 repository, proposing a new syntax for lazy getters, and I was directed to the CONTRIBUTING 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. 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 === 0 ? 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 === 0 ? 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Andrea Giammarchi-2
in case the counter proposal is not clear enough (apologies for that), this should read simpler than that

```js
const take = (n, xs) => n === 0 ? null : xs && {
    head: xs.head,
    lazy tail() {
      const value = take(n - 1, xs.tail);
      Object.defineProperty(this, 'tail', {
        configurable: false,
        get: () => value
      });
      return value;
    }
};
```

Hope it's clear what I'd change.

Best Regards

On Tue, Jun 12, 2018 at 9:45 AM, Andrea Giammarchi <[hidden email]> wrote:
having an extra keyword ...

On Tue, Jun 12, 2018 at 9:44 AM, Andrea Giammarchi <[hidden email]> 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 getish

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 <[hidden email]> wrote:
Hello TC39,

I recently opened an issue in the tc39/ecma262 repository, proposing a new syntax for lazy getters, and I was directed to the CONTRIBUTING 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. 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 === 0 ? 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 === 0 ? 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss





_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Aadit M Shah
In reply to this post by Jordan Harband
When the getter lives on a prototype it would install the memoized value on this using [[Define]]. This is the same way it would work in regular lazy getters:

const defclass = prototype => {
    const constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
};

const Person = defclass({
    constructor: function Person(firstname, lastname) {
        this.firstname = firstname;
        this.lastname  = lastname;
    },
    lazy fullname: this.firstname + " " + this.lastname
});

const john = new Person("John", "Doe");
const jane = new Person("Jane", "Doe");

console.log(john.fullname); // John Doe
console.log(jane.fullname); // Jane Doe

Note that the this within the lazy property value expression (i.e. within the expression this.firstname + " " + this.lastname) refers to the instance (i.e. either john or jane). This can be confusing because without the lazy keyword, this would refer to the lexical context. Although I'm comfortable with it yet I'm open to other suggestions.


On Tue, Jun 12, 2018, at 3:31 AM, Jordan Harband wrote:
How would this work when the getter lives on a prototype? (like most builtin getters) Would it install the memoized value on `this`, or on the object that contains the getter? Would it use [[Set]] or [[Define]]?

On Tue, Jun 12, 2018 at 12:13 AM, Aadit M Shah <[hidden email]> wrote:

Hello TC39,

I recently opened an issue in the tc39/ecma262 repository, proposing a new syntax for lazy getters, and I was directed to the CONTRIBUTING 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. 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 === 0 ? 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 === 0 ? 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 mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Andrea Giammarchi-2
That is why I'm proposing to use a getter, you don't have to reason about the context in `lazy fullname() { return this.firstName + ' ' + this.lastName; }` and it still works with de-contextualized invokes such `lazy random: () => Math.random()` as long as you transpile that as getter calling the right context (when/if needed).

Both cases can de-sugar to same redefinition of a getter.

Regards


On Tue, Jun 12, 2018 at 10:56 AM, Aadit M Shah <[hidden email]> wrote:
When the getter lives on a prototype it would install the memoized value on this using [[Define]]. This is the same way it would work in regular lazy getters:

const defclass = prototype => {
    const constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
};

const Person = defclass({
    constructor: function Person(firstname, lastname) {
        this.firstname = firstname;
        this.lastname  = lastname;
    },
    lazy fullname: this.firstname + " " + this.lastname
});

const john = new Person("John", "Doe");
const jane = new Person("Jane", "Doe");

console.log(john.fullname); // John Doe
console.log(jane.fullname); // Jane Doe

Note that the this within the lazy property value expression (i.e. within the expression this.firstname + " " + this.lastname) refers to the instance (i.e. either john or jane). This can be confusing because without the lazy keyword, this would refer to the lexical context. Although I'm comfortable with it yet I'm open to other suggestions.


On Tue, Jun 12, 2018, at 3:31 AM, Jordan Harband wrote:
How would this work when the getter lives on a prototype? (like most builtin getters) Would it install the memoized value on `this`, or on the object that contains the getter? Would it use [[Set]] or [[Define]]?

On Tue, Jun 12, 2018 at 12:13 AM, Aadit M Shah <[hidden email]> wrote:

Hello TC39,

I recently opened an issue in the tc39/ecma262 repository, proposing a new syntax for lazy getters, and I was directed to the CONTRIBUTING 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. 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 === 0 ? 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 === 0 ? 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 mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Aadit M Shah
In reply to this post by Andrea Giammarchi-2
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 === 0 ? null : xs && {
        head: xs.head,
        get tail() {
            const value = take(n - 1, xs.tail);
            Object.defineProperty(this, "tail", {
                configurable: false,
                get: () => value
            });
            return value;
        }
    };

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.


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 getish

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 <[hidden email]> wrote:

Hello TC39,

I recently opened an issue in the tc39/ecma262 repository, proposing a new syntax for lazy getters, and I was directed to the CONTRIBUTING 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. 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 === 0 ? 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 === 0 ? 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 mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Andrea Giammarchi-2
it's not about being difficult, it's about compatibility with classes, where getters are OK since ever. However, since classes fields are in Stage 3 [1] maybe it's OK to have:

```js
class Test {
  x = 123;
  lazy random = () => this.x + Math.random();
}
```

However, like you've noticed, while it's easy to reason about the context within a class declaration, it's easy to create a footgun outside that.

```js
const test = {
  x: 123,
  lazy random: () => this.x + Math.random()
};
```

That is a whole new meaning of arrow function I'd rather like not to ever encounter.

So what about extra new syntax?

```js
class Test {
  x = 123;
  lazy random() => this.x + Math.random();
}

const test = {
  x: 123,
  lazy random() => this.x + Math.random()
};
```

But I'm pretty sure at methods shorthand discussions that came up and for some reason didn't work.

On Tue, Jun 12, 2018 at 11:32 AM, Aadit M Shah <[hidden email]> 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 === 0 ? null : xs && {
        head: xs.head,
        get tail() {
            const value = take(n - 1, xs.tail);
            Object.defineProperty(this, "tail", {
                configurable: false,
                get: () => value
            });
            return value;
        }
    };

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.


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 getish

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 <[hidden email]> wrote:

Hello TC39,

I recently opened an issue in the tc39/ecma262 repository, proposing a new syntax for lazy getters, and I was directed to the CONTRIBUTING 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. 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 === 0 ? 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 === 0 ? 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 mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Andrea Giammarchi-2
Actually, never mind. I've just realized this would work as well, and it's clean enough.

```js
class Test {
  x = 123;
  lazy random = this.x + Math.random();
}

const test = {
  x: 123,
  lazy random: this.x + Math.random()
};
```

My only concern is if that class method is created N times per each instance (one of the reasons I use lazy getters in classes prototypes instead of per object) as it is AFAIK for current class fields if you attach an arrow function, instead of once per class, which seems to be preferable in a class context.

Otherwise, I'd be happy to see that happen.

Best Regards



On Tue, Jun 12, 2018 at 11:44 AM, Andrea Giammarchi <[hidden email]> wrote:
it's not about being difficult, it's about compatibility with classes, where getters are OK since ever. However, since classes fields are in Stage 3 [1] maybe it's OK to have:

```js
class Test {
  x = 123;
  lazy random = () => this.x + Math.random();
}
```

However, like you've noticed, while it's easy to reason about the context within a class declaration, it's easy to create a footgun outside that.

```js
const test = {
  x: 123,
  lazy random: () => this.x + Math.random()
};
```

That is a whole new meaning of arrow function I'd rather like not to ever encounter.

So what about extra new syntax?

```js
class Test {
  x = 123;
  lazy random() => this.x + Math.random();
}

const test = {
  x: 123,
  lazy random() => this.x + Math.random()
};
```

But I'm pretty sure at methods shorthand discussions that came up and for some reason didn't work.

On Tue, Jun 12, 2018 at 11:32 AM, Aadit M Shah <[hidden email]> 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 === 0 ? null : xs && {
        head: xs.head,
        get tail() {
            const value = take(n - 1, xs.tail);
            Object.defineProperty(this, "tail", {
                configurable: false,
                get: () => value
            });
            return value;
        }
    };

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.


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 getish

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 <[hidden email]> wrote:

Hello TC39,

I recently opened an issue in the tc39/ecma262 repository, proposing a new syntax for lazy getters, and I was directed to the CONTRIBUTING 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. 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 === 0 ? 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 === 0 ? 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 mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Herby Vojčík
In reply to this post by Andrea Giammarchi-2


On June 12, 2018 9:44:31 AM GMT+02:00, Andrea Giammarchi <[hidden email]> 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.

Yeah I find this better.

Also fixes the this questions by unambiguously setting it to the instance.

>*## Keep it getish*
>
>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,

Why enforcing configurable false? When you use get x() / set x() syntax, it leaves the thing configurable true. I feel it is more consistent to have the replaced getter copy configurable from existing status quo, that is, what is actual configurable of this.tail.

And of course, Object.defineProperty family needs a way to create this, I think {get: getterFn, lazy: true, …} could work.

Herby

>        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.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Aadit M Shah
In reply to this post by Andrea Giammarchi-2
Classes in JavaScript don't allow assignments within the class body. Hence, the following code is invalid:

class Test {
    x = 123; // This throws an error.
    lazy random = this.x + Math.random(); // Similarly, this should be invalid.
}

Hence, the more I think about it the more it makes sense to use the following syntax instead:

const zeros = { head: 0, lazy tail() { return this; } };

class Random {
    lazy random() { return Math.random(); }
}

const x = new Random;
const y = new Random;

console.log(x.value === x.value); // true
console.log(x.value === y.value); // false (in all probability)

It's more verbose than my initial proposal. However, as Andrea mentioned it's consistent with the class method syntax and the this keyword can be used within the lazy getter without causing confusion.

Finally, I think that `lazy <name>() { <body> }` should be syntactic sugar for:

get name() {
    return Object.defineProperty(this, "<name>", {
        value: (function () { <body> }()),
        configurable: false // Making it non-configurable is debatable.
    }).<name>;
}

Using Object.defineProperty instead of simple assignment will ensure that it works in strict mode. In addition, it'll make the property non-writable which is the behavior we want because it's non-writable before memoization too, since it doesn't have a setter.


On Tue, Jun 12, 2018, at 5:52 AM, Andrea Giammarchi wrote:
Actually, never mind. I've just realized this would work as well, and it's clean enough.

```js
class Test {
  x = 123;
  lazy random = this.x + Math.random();
}

const test = {
  x: 123,
  lazy random: this.x + Math.random()
};
```

My only concern is if that class method is created N times per each instance (one of the reasons I use lazy getters in classes prototypes instead of per object) as it is AFAIK for current class fields if you attach an arrow function, instead of once per class, which seems to be preferable in a class context.

Otherwise, I'd be happy to see that happen.

Best Regards



On Tue, Jun 12, 2018 at 11:44 AM, Andrea Giammarchi <[hidden email]> wrote:
it's not about being difficult, it's about compatibility with classes, where getters are OK since ever. However, since classes fields are in Stage 3 [1] maybe it's OK to have:

```js
class Test {
  x = 123;
  lazy random = () => this.x + Math.random();
}
```

However, like you've noticed, while it's easy to reason about the context within a class declaration, it's easy to create a footgun outside that.

```js
const test = {
  x: 123,
  lazy random: () => this.x + Math.random()
};
```

That is a whole new meaning of arrow function I'd rather like not to ever encounter.

So what about extra new syntax?

```js
class Test {
  x = 123;
  lazy random() => this.x + Math.random();
}

const test = {
  x: 123,
  lazy random() => this.x + Math.random()
};
```

But I'm pretty sure at methods shorthand discussions that came up and for some reason didn't work.

On Tue, Jun 12, 2018 at 11:32 AM, Aadit M Shah <[hidden email]> 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 === 0 ? null : xs && {
        head: xs.head,
        get tail() {
            const value = take(n - 1, xs.tail);
            Object.defineProperty(this, "tail", {
                configurable: false,
                get: () => value
            });
            return value;
        }
    };

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.


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 getish

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 <[hidden email]> wrote:

Hello TC39,

I recently opened an issue in the tc39/ecma262 repository, proposing a new syntax for lazy getters, and I was directed to the CONTRIBUTING 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. 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 === 0 ? 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 === 0 ? 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 mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Herby Vojčík
In reply to this post by Aadit M Shah


On June 12, 2018 11:32:22 AM GMT+02:00, Aadit M Shah <[hidden email]> 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
>> <[hidden email]> 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
>>> [hidden email]
>>> 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
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Andrea Giammarchi-2
In reply to this post by Herby Vojčík
Why enforcing configurable false?

The fact the lazy getter is called getter, and the fact that a getter cannot be assigned or the engine throws errors, as opposite of a non configurable property that will silently ignore the assignment, makes me think substituting a lazy getter with a fixed getter is the way to.

But I also think being lazy, usually meaning with expensive computations needed once only, it's a nice to have, and clean guard, to fix that getter forever.

However, that creates observability of the getter, through its own property descriptor, but also, as a getter, it might signal side effects, while a fixed property on the object set as value would indicate there are, probably, no side effects in accessing it.

TL;DR I'm not fully sure about the getter should be defined, if through its inherited definition but with a different get callback that returns the computed value, and only when it comes to classes, or through its own property accessor, when it comes to objects.

Maybe this is the best way to go though, so that the following code:

```js
const test = {
  x: 123,
  lazy random() {
    return this.x + Math.random();
  }
};

class Test {
  x = 123;
  lazy random() {
    return this.x + Math.random();
  }
}
```

would de-sugar in something like this:

```js
const getDescriptor = (o, k) => (
  o ? (
    Object.getOwnPropertyDescriptor(o, k) ||
    getDescriptor(Object.getPrototypeOf(o), k)
  ) : o
);

const test = {
  x: 123,
  get random() {
    const desc = getDescriptor(this, 'random');
    const value = (function () {
      return this.x + Math.random();
    }).call(this);
    desc.get = () => value;
    Object.defineProperty(this, 'random', desc);
    return value;
  }
};

class Test {
  x = 123;
  get random() {
    const desc = getDescriptor(this, 'random');
    const value = (function () {
      return this.x + Math.random();
    }).call(this);
    desc.get = () => value;
    Object.defineProperty(this, 'random', desc);
    return value;
  }
}
```

preserving whatever behavior previously defined.



On Tue, Jun 12, 2018 at 1:14 PM, <[hidden email]> wrote:


On June 12, 2018 9:44:31 AM GMT+02:00, Andrea Giammarchi <[hidden email]> 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.

Yeah I find this better.

Also fixes the this questions by unambiguously setting it to the instance.

>*## Keep it getish*
>
>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,

Why enforcing configurable false? When you use get x() / set x() syntax, it leaves the thing configurable true. I feel it is more consistent to have the replaced getter copy configurable from existing status quo, that is, what is actual configurable of this.tail.

And of course, Object.defineProperty family needs a way to create this, I think {get: getterFn, lazy: true, …} could work.

Herby

>        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.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Herby Vojčík
In reply to this post by Herby Vojčík


On June 12, 2018 1:32:04 PM GMT+02:00, [hidden email] wrote:
>This autofreezing if the value sticks out out this philosophy of "

_of_ the value

>malleable unless specified otherwise".
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Aadit M Shah
In reply to this post by Herby Vojčík
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. Hence, from what I understand we're considering the following syntax:

const zeros = { head: 0, 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: 0,
    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, [hidden email] wrote:


On June 12, 2018 11:32:22 AM GMT+02:00, Aadit M Shah <[hidden email]> 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
<[hidden email]> 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



Links:

4.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

T.J. Crowder-2
In reply to this post by Aadit M Shah
On Tue, Jun 12, 2018 at 12:31 PM, Aadit M Shah <[hidden email]> wrote:
> Classes in JavaScript don't allow assignments within the class body. Hence,
> the following code is invalid:
>
> class Test {
>     x = 123; // This throws an error.
>     lazy random = this.x + Math.random(); // Similarly, this should be
> invalid.
> }

Andrea was using syntax from the [class fields proposal][1], currently at Stage 3 and fairly commonly used via transpilation (he said "class fields" later in the post, but didn't emphasize it).

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Andrea Giammarchi-2
In reply to this post by Herby Vojčík
forgot about this:

I think {get: getterFn, lazy: true, …} could work.

sort of, because descriptors can be only for properties or accessors, but lazy + set, as accessor might look weird.

However, if I can dare bringing in another use case I have daily in my code, I have a case for having a setter that defines the getter if explicit, so that by default I have a lazy getter, but if before it gets used somebody sets the property, it overrides the lazy getter.

This might happen, as example, during constructor time, as opposite of after initialization.

Example:

```js
class Weirdo {
  constructor(theThing = null) {
    if (theThing != null) {
      this.theThing = theThing;
    }
  }
  get theThing() {
    const value = doVeryExpensiveThing();
    Object.defineProperty(this, 'theThing', {
      get: () => value
    });
    return value;
  }
  set theThing(value) {
    Object.defineProperty(this, 'theThing', {
      get: () => value
    });
  }
}
```

Honestly, I don't see why this would create any issue with the accessor descriptor, so that I can `lazy theThing() { return doVeryExpensiveThing(); }` and eventually provide a `set theThing() {}` to do whatever I want to do when, and if, needed.

So yes, if `lazy: true` plays well with accessors, and it's to define the special `get` behavior only, then it's a valid welcome, and nice to have addition.

```js
Object.defineProperty(
  test,
  'random',
  {
    configurable: false, // by default
    enumerable: false, // by default
    lazy: false, // by default
    get() { return this.x + Math.random(); },
    set() { /* optional, do whatever */ }
  }
);
```

My last question / concern at this point, in case descriptors should be part of this proposal, is how to retrieve the initial lazy descriptor from an object which lazy getter overwrote such value, but I also think this should not be a real-world concern or, eventually, a must know caveat for functional programmers that play procedurally with accessors.

I think I've exposed all my thoughts on this issue, I'll hope for some extra outcome.

Best Regards


On Tue, Jun 12, 2018 at 1:14 PM, <[hidden email]> wrote:


On June 12, 2018 9:44:31 AM GMT+02:00, Andrea Giammarchi <[hidden email]> 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.

Yeah I find this better.

Also fixes the this questions by unambiguously setting it to the instance.

>*## Keep it getish*
>
>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,

Why enforcing configurable false? When you use get x() / set x() syntax, it leaves the thing configurable true. I feel it is more consistent to have the replaced getter copy configurable from existing status quo, that is, what is actual configurable of this.tail.

And of course, Object.defineProperty family needs a way to create this, I think {get: getterFn, lazy: true, …} could work.

Herby

>        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.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Herby Vojčík
In reply to this post by Aadit M Shah
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 <[hidden email]> 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, [hidden email] wrote:
>>
>>
>> On June 12, 2018 11:32:22 AM GMT+02:00, Aadit M Shah
>> <[hidden email]> 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
>>>> <[hidden email]> 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
>>>>> [hidden email]
>>>>> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: [Proposal] New syntax for lazy getters

Herby Vojčík


On June 12, 2018 2:37:05 PM GMT+02:00, [hidden email] 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.

Not to create a confusion, I _do_not_ propose that both ways be working, what I wanted to say is that only o e should be chosen, and that will select what will be there as a replacement.

Though, now that I think about it,

  lazy field = expr;

and

  lazy getter() { return expr; }

are different beasts.

Anyway, as Andrea said, enough said for the moment.

>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
><[hidden email]> 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, [hidden email] wrote:
>>>
>>>
>>> On June 12, 2018 11:32:22 AM GMT+02:00, Aadit M Shah
>>> <[hidden email]> 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
>>>>> <[hidden email]> 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
>>>>>> [hidden email]
>>>>>> 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
>[hidden email]
>https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
12