I'm surprised no-one has mentioned memoization yet. A lazy constant can be modelled with memoization of a nullary function. Memoization only works when you have defined a concept of *value* for the argument pack (to act as the cache key), which IMO is probably best dealt with by something like Immutable.js. The 0 argument "constant" case is trivial and need not invoke something like Immutable, but I'd rather try to consider approaching something a little more general than just "lazy values".
```js const memoize = fn => /* some definition based on Immutable values as function arguments */; const expensiveToRetrieve = memoize(() => whatever); const fastestRoute = memoize((pointA, pointB) => whatever); ``` With freestanding "getters" you could even have these resembling normal variables without the need for `()`. Not sure where we stand on that though. Alex On 31 August 2017 at 21:53, Michał Wadas <[email protected]> wrote: > 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" <[email protected]> > 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 <[email protected]> > 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 >> [email protected] >> >> 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 >> <[email protected]> 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 <[email protected]> >> > wrote: >> >> >> >> It takes a function, and returns a function that (if necessary) >> >> initializes the value and then gets it. >> >> ----- >> >> >> >> Isiah Meadows >> >> [email protected] >> >> >> >> 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 >> >> <[email protected]> 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 < >> [email protected]> >> >> > 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 >> >> >> <[email protected]> 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 >> >> >> > <[email protected]> >> >> >> > 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 >> >> >> >> [email protected] >> >> >> >> >> >> >> >> 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 >> >> >> >> <[email protected]> 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 >> >> >> >> > <[email protected]> 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/Clas >> s.md#classlazycallback >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> On Thu, Aug 31, 2017 at 6:03 PM, Isiah Meadows >> >> >> >> >> <[email protected]> >> >> >> >> >> 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 >> >> >> >> >>> [email protected] >> >> >> >> >>> >> >> >> >> >>> 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 >> >> >> >> >>> <[email protected]> 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 >> >> >> >> >>> > <[email protected]> >> >> >> >> >>> > 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 >> >> >> >> >>> >> [email protected] >> >> >> >> >>> >> >> >> >> >> >>> >> 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 >> >> >> >> >>> >> <[email protected]> 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 >> >> >> >> >>> >> > <[email protected]> >> >> >> >> >>> >> > 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 >> >> >> >> >>> >> >> [email protected] >> >> >> >> >>> >> >> >> >> >> >> >>> >> >> 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 >> >> >> >> >>> >> >> <[email protected]> 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 >> >> >> >> >>> >> >> > <[email protected]> >> >> >> >> >>> >> >> > 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 >> >> >> >> >>> >> >> >> [email protected] >> >> >> >> >>> >> >> >> >> >> >> >> >>> >> >> >> Looking for web consulting? Or a new website? >> >> >> >> >>> >> >> >> Send me an email and we can get started. >> >> >> >> >>> >> >> >> www.isiahmeadows.com >> >> >> >> >>> >> >> >> _______________________________________________ >> >> >> >> >>> >> >> >> es-discuss mailing list >> >> >> >> >>> >> >> >> [email protected] >> >> >> >> >>> >> >> >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> >> >>> >> >> > >> >> >> >> >>> >> >> > >> >> >> >> >>> >> > >> >> >> >> >>> >> > >> >> >> >> >>> > >> >> >> >> >>> > >> >> >> >> >> >> >> >> >> >> >> >> >> >> > >> >> >> > >> >> >> > >> >> >> >> >> >> ----- >> >> >> >> >> >> Isiah Meadows >> >> >> [email protected] >> >> >> >> >> >> Looking for web consulting? Or a new website? >> >> >> Send me an email and we can get started. >> >> >> www.isiahmeadows.com >> >> > >> >> > >> > >> > >> > > > _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss > > > > _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss > >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

