Lazy evaluation
Michał Wadas
michalwadas at gmail.com
Thu Aug 31 20:53:52 UTC 2017
Why not something like decorators (not sure if decorator proposal covers
this already)?
class Foo {
@cached
get bar() {
return something(this);
}
}
On 31 Aug 2017 10:30 pm, "Andrea Giammarchi" <andrea.giammarchi at gmail.com>
wrote:
it's a matter of semantics.
If I see this
```js
var later = anyWrappingName(() => Math.random());
// this is an assumption, not something obvious
later() === later()
```
If instead, I write this:
```js
this.later === this.later;
```
I expect that to never possibly fail like `arr.length === arr.length` or
any `obj.prop`, in APIs with common sense, are equal to `obj.prop`.
Invokes via instances and objects? It's never obvious at first look, if
that is a method execution, but it's surely a new invoke.
If you've trapped once the result behind the scene, reading that, is just
noise for anyone eyes.
So, once again, are we proposing something that results into exactly this?
```js
class Later {
get thing() {
return Object.defineProperty(this, 'thing', {value: anyLazy()});
}
constructor() {
// always true, no matter when/where
this.thing === this.thing;
}
}
```
If so, I'm happy. If not, this is confusing and solving not much.
Best Regards
On Thu, Aug 31, 2017 at 9:14 PM, Isiah Meadows <isiahmeadows at gmail.com>
wrote:
> 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-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/isiahm
> eadows/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
> >> >
> >> >
> >
> >
>
_______________________________________________
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/33b30c2c/attachment-0001.html>
More information about the es-discuss
mailing list