Lazy evaluation
Isiah Meadows
isiahmeadows at gmail.com
Thu Aug 31 19:18:46 UTC 2017
Note the TS-ish declaration above it. That's the variant I was
referring to (I presented about 3 different variants initially).
```ts
// The declaration I included
declare function lazy<T>(init: () => T): () => T;
```
On Thu, Aug 31, 2017 at 3:05 PM, Andrea Giammarchi
<andrea.giammarchi at gmail.com> wrote:
> it wouldn't work, would it ? I mean, you still have to pass through the
> "ugly" _db.get() thingy, right?
>
> how do you access and trigger the lazy bit within the class?
>
> On Thu, Aug 31, 2017 at 7:56 PM, Isiah Meadows <isiahmeadows at gmail.com>
> wrote:
>>
>> What about this (using the stage 3 class fields proposal)?
>>
>> ```js
>> declare function lazy<T>(init: () => T): () => T;
>>
>> class WithLazyVals {
>> _db = lazy(() => new Promise(...));
>> }
>> ```
>> -----
>>
>> 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 1:34 PM, Andrea Giammarchi
>> <andrea.giammarchi at gmail.com> wrote:
>> >> 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-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
>> >>> >> >> >
>> >>> >> >> >
>> >>> >> >
>> >>> >> >
>> >>> >
>> >>> >
>> >>
>> >>
>> >
>
>
-----
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
More information about the es-discuss
mailing list