Lazy evaluation
Isiah Meadows
isiahmeadows at gmail.com
Thu Aug 31 20:14:13 UTC 2017
Yes. I'll point out that having it as a function, rather than a
property-specific thing, makes it more flexible, since you can define
constants as lazy values (I do that in quite a few places).
If you want to make it transparent, it's not that hard to make a
single-line getter/method that hides the abstraction.
Granted, most of my lazy values are properties, not constants, so I
could consider it an acceptable compromise.
-----
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 3:54 PM, Andrea Giammarchi
<andrea.giammarchi at gmail.com> wrote:
> so in JavaScript that results into this._db() each time, resolved lazily
> with the first value returned once ?
>
> I still think my approach is cleaner and more transparent.
>
> `get _thing() { return defineProperty(this, 'thing', value) }`
>
> but if your TS-ish stuff translates into that, works for me
>
>
>
> On Thu, Aug 31, 2017 at 8:49 PM, Isiah Meadows <isiahmeadows at gmail.com>
> wrote:
>>
>> It takes a function, and returns a function that (if necessary)
>> initializes the value and then gets it.
>> -----
>>
>> 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 3:43 PM, Andrea Giammarchi
>> <andrea.giammarchi at gmail.com> wrote:
>> > Sorry I don't speak TS, I speak ES.
>> >
>> > Can you please tell me in JavaScript what does that do?
>> >
>> > On Thu, Aug 31, 2017 at 8:18 PM, Isiah Meadows <isiahmeadows at gmail.com>
>> > wrote:
>> >>
>> >> 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