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 m...@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.giammar...@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.giammar...@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 <isiahmead...@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 >>> m...@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.giammar...@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 <isiahmead...@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 >>> >> m...@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.giammar...@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 >>> >> > <isiahmead...@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 >>> >> >> m...@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.giammar...@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 >>> >> >> > <isiahmead...@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 >>> >> >> >> m...@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@mozilla.org >>> >> >> >> https://mail.mozilla.org/listinfo/es-discuss >>> >> >> > >>> >> >> > >>> >> > >>> >> > >>> > >>> > >> >> > _______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss