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/Class.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-initialization-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/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 >> >>> >> >> >> [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

