Lazy evaluation

Andrea Giammarchi andrea.giammarchi at gmail.com
Thu Aug 31 17:25:32 UTC 2017


> How often do you start out with a class like this ...

Never, like I've said. This is the lazy pattern I know since ever.

```js
class Foo {
  get _db() {
    return Object.defineProperty(this, '_db', {
      value: new Promise((resolve, reject) => {
        // open a database connection
        // set up whatever tables you need to
        // etc.
      })
    })._db;
  }
}
```

Whenever you need, you just access `this._db`, no need to create an
enumerable variable and a class method.

It looks cleaner to me.


> Things you don't want to initialize right away because initialization

You don't really have to convince me, I've written lazy properties since
getters and setters were introduced [1]

All I am saying is that this proposal doesn't compose well with classes,
it's just yet another SuperPrimitive for the language.

It is also something trivial to implement on user land, yet I haven't seen
many writing code like the following:

```js
function Lazy(fn) {
  let c = false, v;
  return {get(){ return c ? v : (c = !c, v = fn()) }};
}

var o = Lazy(() => Math.random());
o.get(); // ...
```

Maybe it's me that hasn't seen this widely adopted from some library?

Anyway, this is just my opinion, maybe others would be happy with this.

Best Regards

[1] Class.lazy example
https://github.com/WebReflection/prototypal/blob/master/Class.md#classlazycallback



On Thu, Aug 31, 2017 at 6:03 PM, Isiah Meadows <isiahmeadows at gmail.com>
wrote:

> It'd solve a problem similarly to Kotlin's `by lazy { ... }` delegate,
> .NET's `System.Lazy<T>`, Swift's `lazy var`, among many other
> languages. It's very useful for lazy initialization [1], such as
> lazily setting up a database, requesting a resource, among other
> costly things. [2]
>
> How often do you start out with a class like this, where you have an
> expensive resource you don't want to open right away?
>
> ```js
> class Foo {
>     constructor() {
>         this._db = undefined
>     }
>
>     _initDb() {
>         if (this._db) return this._db
>         return this._db = new Promise((resolve, reject) => {
>             // open a database connection
>             // set up whatever tables you need to
>             // etc.
>         })
>     }
> }
> ```
>
> Or maybe, a large lookup table that takes a while to build, and might
> not even be used, so you don't want to do it on load?
>
> ```js
> var table
>
> function initTable() {
>     if (table) return
>     table = new Array(10000)
>     // do some expensive calculations
> }
> ```
>
> Things you don't want to initialize right away because initialization
> is expensive and/or the value might not even be used. That's the
> problem I'm aiming to solve, and it's something I feel would be useful
> in its own right in the language, about equal in importance to weak
> references. (Slightly specialized, but the need is not non-zero.)
>
> [1]: https://en.wikipedia.org/wiki/Lazy_initialization
> [2]: https://stackoverflow.com/questions/978759/what-is-lazy-
> initialization-and-why-is-it-useful
> -----
>
> Isiah Meadows
> me at isiahmeadows.com
>
> Looking for web consulting? Or a new website?
> Send me an email and we can get started.
> www.isiahmeadows.com
>
>
> On Thu, Aug 31, 2017 at 12:23 PM, Andrea Giammarchi
> <andrea.giammarchi at gmail.com> wrote:
> > right ... so ... I'm not sure I understand what this proposal would
> solve.
> >
> > Instead of this:
> > ```js
> > obj.val || (obj.val = getValue())
> > ```
> >
> > you want to do this
> > ```js
> > (obj.val || (obj.val = new Lazy(getValue)).get();
> > ```
> >
> > Where is the "win" and why is that?
> >
> >
> >
> > On Thu, Aug 31, 2017 at 5:18 PM, Isiah Meadows <isiahmeadows at gmail.com>
> > wrote:
> >>
> >> With my proposed `Lazy` class, if you were to use an instance as a
> >> descriptor, the `this` value it'd receive would not be a `Lazy`
> >> instance like it'd expect.
> >>
> >> Consider it the difference between `a.self` and `b.get()` in your
> >> example. `b.get()` is what I'd be expecting.
> >> -----
> >>
> >> Isiah Meadows
> >> me at isiahmeadows.com
> >>
> >> Looking for web consulting? Or a new website?
> >> Send me an email and we can get started.
> >> www.isiahmeadows.com
> >>
> >>
> >> On Thu, Aug 31, 2017 at 12:12 PM, Andrea Giammarchi
> >> <andrea.giammarchi at gmail.com> wrote:
> >> >> using it in a descriptor would get it passed the wrong `this`
> >> >
> >> > sorry, what?
> >> >
> >> > ```js
> >> > var a = {};
> >> > var b = {get() { return this; }};
> >> > Object.defineProperty(a, 'self', b);
> >> >
> >> > a.self === a; // true
> >> > ```
> >> >
> >> >
> >> > On Thu, Aug 31, 2017 at 5:09 PM, Isiah Meadows <
> isiahmeadows at gmail.com>
> >> > wrote:
> >> >>
> >> >> No. `Lazy` is intended to be an object to be used directly, not a
> >> >> descriptor of any kind.
> >> >>
> >> >> (My `lazy.get()` is an unbound method, so using it in a descriptor
> >> >> would get it passed the wrong `this`.)
> >> >> -----
> >> >>
> >> >> Isiah Meadows
> >> >> me at isiahmeadows.com
> >> >>
> >> >> Looking for web consulting? Or a new website?
> >> >> Send me an email and we can get started.
> >> >> www.isiahmeadows.com
> >> >>
> >> >>
> >> >> On Thu, Aug 31, 2017 at 9:39 AM, Andrea Giammarchi
> >> >> <andrea.giammarchi at gmail.com> wrote:
> >> >> > the following is how I usually consider lazy values
> >> >> >
> >> >> > ```js
> >> >> > class Any {
> >> >> >   _lazy(name) {
> >> >> >     switch (name) {
> >> >> >       case 'uid': return Math.random();
> >> >> >       // others ... eventually
> >> >> >     }
> >> >> >   }
> >> >> >   get uid() {
> >> >> >     var value = this._lazy('uid');
> >> >> >     // from now on, direct access
> >> >> >     Object.defineProperty(this, 'uid', {value});
> >> >> >     return value;
> >> >> >   }
> >> >> > }
> >> >> >
> >> >> > const a = new Any;
> >> >> > a.uid === a.uid; // true
> >> >> > ```
> >> >> >
> >> >> > If I understand correctly your proposal is to use Lazy as generic
> >> >> > descriptor, is that correct ?
> >> >> >
> >> >> > ```js
> >> >> > Object.defineProperty({}, 'something', new Lazy(function (val) {
> >> >> >   return this.shakaLaka ? val : 'no shakaLaka';
> >> >> > }));
> >> >> > ```
> >> >> >
> >> >> > ???
> >> >> >
> >> >> > If that's the case I see already people confused by arrow function
> >> >> > in case they need to access the context,
> >> >> > plus no property access optimization once resolved.
> >> >> >
> >> >> > It's also not clear if such property can be set again later on
> (right
> >> >> > now it
> >> >> > cannot)
> >> >> > 'cause lazy definition doesn't always necessarily mean inability to
> >> >> > reassign.
> >> >> >
> >> >> > What am I missing/misunderstanding?
> >> >> >
> >> >> > Regards
> >> >> >
> >> >> >
> >> >> >
> >> >> > On Thu, Aug 31, 2017 at 2:21 PM, Isiah Meadows
> >> >> > <isiahmeadows at gmail.com>
> >> >> > wrote:
> >> >> >>
> >> >> >> It'd be really nice if lazy values made it into the spec somehow.
> >> >> >> I've
> >> >> >> already found myself using things like this [1] quite a bit, and
> >> >> >> I've
> >> >> >> also found myself frequently initializing properties not on first
> >> >> >> access.
> >> >> >>
> >> >> >> [1]:
> >> >> >>
> >> >> >> https://gist.github.com/isiahmeadows/
> 4c0723bdfa555a1c2cb01341b323c3d4
> >> >> >>
> >> >> >> As for what would be a nice API, maybe something like one of
> these?
> >> >> >>
> >> >> >> ```js
> >> >> >> class Lazy<T> {
> >> >> >>     constructor(init: () => T);
> >> >> >>     get(): T; // or error thrown
> >> >> >> }
> >> >> >>
> >> >> >> function lazy<T>(init: () => T): () => T; // or error thrown
> >> >> >>
> >> >> >> function lazy<T>(init: () => T): {
> >> >> >>     get(): T; // or error thrown
> >> >> >> }
> >> >> >> ```
> >> >> >>
> >> >> >> Alternatively, syntax might work, with `do` expression semantics:
> >> >> >>
> >> >> >> ```js
> >> >> >> const x = lazy do { ... }
> >> >> >> // expose via `x.get()` or just `x()`
> >> >> >> ```
> >> >> >>
> >> >> >> -----
> >> >> >>
> >> >> >> Isiah Meadows
> >> >> >> me at isiahmeadows.com
> >> >> >>
> >> >> >> Looking for web consulting? Or a new website?
> >> >> >> Send me an email and we can get started.
> >> >> >> www.isiahmeadows.com
> >> >> >> _______________________________________________
> >> >> >> es-discuss mailing list
> >> >> >> es-discuss at mozilla.org
> >> >> >> https://mail.mozilla.org/listinfo/es-discuss
> >> >> >
> >> >> >
> >> >
> >> >
> >
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170831/d633d8ca/attachment-0001.html>


More information about the es-discuss mailing list