Lazy evaluation

Andrea Giammarchi andrea.giammarchi at gmail.com
Thu Aug 31 17:34:16 UTC 2017


> this proposal doesn't compose well with classes

to expand a little, if you were proposing

```js
class WithLazyVals {
  lazy _db() { return new Promise(...); }
}
```

I would've taken first flight to come over and hug you.

Best Regards




On Thu, Aug 31, 2017 at 6:25 PM, Andrea Giammarchi <
andrea.giammarchi at gmail.com> wrote:

> > 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-init
>> ialization-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/4c0723bdfa555a1c2cb0134
>> 1b323c3d4
>> >> >> >>
>> >> >> >> 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/c000f5fa/attachment-0001.html>


More information about the es-discuss mailing list