Lazy evaluation

Andrea Giammarchi andrea.giammarchi at gmail.com
Thu Sep 14 09:26:46 UTC 2017


> please use normal method-calls instead, which are more maintainable

no, thanks.


> WeakMap's implicit-garbage-collecting feature is error-prone, hard to
validate with tests, and generally becomes unmaintainable over time.

no, thanks.

We were discussing patterns here, nothing to "please don't" and IMO, dogma
oriented rules are over-engineered anti-pattern too.

Let's not make this ML an awkward place for who wants to just learn or
explore JS language features, thanks.



On Thu, Sep 14, 2017 at 9:55 AM, kai zhu <kaizhu256 at gmail.com> wrote:

> inline
>
> ```js
>> class A {
>>   #random;
>>   get random() {
>>     return this.#random ||
>>           (this.#random = Math.random());
>>   }
>> }
>>
>>
>> // transpiled
>> var A = function (wm) {
>>   function A() {
>>     wm.set(this, {random: void 0});
>>   }
>>   Object.defineProperties(
>>     A.prototype,
>>     {
>>       random: {
>>         configurable: true,
>>         get: function () {
>>           return wm.get(this).random ||
>>                 (wm.get(this).random = Math.random());
>>         }
>>       }
>>     }
>>   );
>>   return A;
>> }(new WeakMap);
>> ```
>
>
> - overloaded getters/setters and Object.defineProperties are generally *over-engineered
> *anti-patterns in javascript-programming
> * please use normal method-calls instead, which are more maintainable
>
> - WeakMap is an *over-engineered *anti-pattern in javascript-programming
> * they are inferior to using a plain-object cache-dictionary in pretty
> much every use-case.
> * WeakMap's implicit-garbage-collecting feature is error-prone, hard to
> validate with tests, and generally becomes unmaintainable over time.
>
> ```javascript
> /*jslint node: true */
> 'use strict';
>
> function LazyClass() {
>     this.cacheDict = {};
> }
> LazyClass.prototype.getRandomCached = function () {
>     this.cacheDict.random = this.cacheDict.random || Math.random();
>     return this.cacheDict.random;
> };
> LazyClass.prototype.clearCache = function () {
>     this.cacheDict = {};
> };
>
> var lazyObject = new LazyClass();
> console.log(lazyObject.getRandomCached());
> console.log(lazyObject.getRandomCached());
> lazyObject.clearCache();
> console.log(lazyObject.getRandomCached());
> ```
>
>
>
>
> On Sep 13, 2017, at 9:32 PM, Andrea Giammarchi <
> andrea.giammarchi at gmail.com> wrote:
>
> > Maybe you mean "will behave more or less as if (except more
> efficiently)"?
>
> no, I meant: it will transpiled into something using private WeakMaps.
>
> I don't have any interest in talk nanoseconds for something unrelated to
> the topic though.
>
> Best Regards
>
> On Wed, Sep 13, 2017 at 1:54 PM, Alex Kodat <alexkodat at gmail.com> wrote:
>
>> What do you mean by “will be transpiled through”? My understanding of the
>> private property proposal is that private properties will be in fixed slots
>> (inaccessible outside the class) in the object so there would be no
>> WeakMap. Maybe you mean "will behave more or less as if (except more
>> efficiently)"?
>>
>> ----
>> Alex Kodat
>>
>> From: es-discuss [mailto:es-discuss-bounces at mozilla.org] On Behalf Of
>> Andrea Giammarchi
>> Sent: Wednesday, September 13, 2017 2:31 AM
>> To: Steve Fink <sphink at gmail.com>
>> Cc: es-discuss at mozilla.org
>> Subject: Re: Lazy evaluation
>>
>> > The properties already existed, so defineProperty shouldn't modify the
>> order IIUC
>>
>> well, nope. the property existed in the prototype, not in the object.
>>
>> anyway, I guess private properties, that are a possible solution, will be
>> transpiled through a WeakMap so that most likely anything discussed in here
>> won't make sense and the future code would look like the following
>>
>> ```js
>> class A {
>>   #random;
>>   get random() {
>>     return this.#random ||
>>           (this.#random = Math.random());
>>   }
>> }
>>
>>
>> // transpiled
>> var A = function (wm) {
>>   function A() {
>>     wm.set(this, {random: void 0});
>>   }
>>   Object.defineProperties(
>>     A.prototype,
>>     {
>>       random: {
>>         configurable: true,
>>         get: function () {
>>           return wm.get(this).random ||
>>                 (wm.get(this).random = Math.random());
>>         }
>>       }
>>     }
>>   );
>>   return A;
>> }(new WeakMap);
>> ```
>>
>>
>>
>>
>>
>>
>> On Tue, Sep 12, 2017 at 10:39 PM, Steve Fink <mailto:sphink at gmail.com>
>> wrote:
>> My intent was only to respond to the performance analysis, specifically
>> the implication that the only performance cost is in building the new
>> hidden class. That is not the case; everything that touches those objects
>> is affected as well.
>>
>> Whether or not it's still the right way to accomplish what you're after,
>> I wasn't venturing an opinion. I could probably come up with a benchmark
>> showing that your WeakMap approach can be faster -- eg by only accessing
>> the property once, but feeding the old and new versions of the object into
>> code that executes many many many times (doing something that never looks
>> at that property, but is now slightly slower because it isn't monomorphic).
>> But I suspect that for practical usage, redefining the property *is* faster
>> than a WeakMap.
>>
>> If I were to look beyond for other solutions for your problem, then I'm
>> just speculating. Can decorators populate multiple properties once the
>> expensive work is done?
>>
>> I really want to tell the VM what's going on. I guess if it knew that
>> accessing a getter property would convert it into a value property, and
>> that it was doing something that would access the getter, then it could
>> know to use the outgoing shape instead of the incoming shape. If only it
>> knew that the getter was pure... but that way lies madness.
>>
>> Given that most code that would slow down would also trigger the lazy
>> defineProperty(), it's really not going to be that much of an issue. Any
>> access after the first will see a single shape.
>>
>> meh. Just take the perf hit, with awareness that you may be triggering
>> slight slowdowns in all users of that object. Or you might not. I doubt
>> it'll be that big, since you'll probably just end up with an inline cache
>> for both shapes and there won't be all that much to optimize based on
>> knowing a single shape.
>>
>> Oh, and I think I was wrong about property enumeration order. The
>> properties already existed, so defineProperty shouldn't modify the order
>> IIUC. (I am awful with language semantics.)
>>
>> On 9/11/17 2:48 PM, Andrea Giammarchi wrote:
>> Steve it's not solved in any other way. Even if you use a WeakMap with an
>> object, you gonna lazy attach properties to that object.
>>
>> I honestly would like to see alternatives, if any, 'cause so far there is
>> a benchmark and it proves already lazy property assignment is around 4x
>> faster.
>>
>> So, it's easy to say "it's not the best approach" but apparently hard to
>> prove that's the case?
>>
>> Looking forward to see better alternatives.
>>
>>
>> On Mon, Sep 11, 2017 at 8:15 PM, Steve Fink <mailto:sphink at gmail.com>
>> wrote:
>> On 9/11/17 5:36 AM, Matthew Robb wrote:
>> > I think it's irrelevant if internally VMs are not too happy. VMs are
>> there to solve our problems, not vice-versa ;-)
>>>> This ^​ is very important for everyone to get on board with. Regardless
>> the cost should be negligible as the shape is only changing at the point of
>> delayed init. This will cause, for example V8, to deop the object and have
>> to build a new hidden class but only the one time. I guess it would
>> potentially be interesting to support an own property that when undefined
>> would delegate up the proto chain.
>>
>> (I don't know, but) I would expect it to be worse than this. The shape is
>> changing at the point of delayed init, which means that if an engine is
>> associating the possible set of shapes with the constructor (or some other
>> form of allocation site + mandatory initialization), then that site will
>> produce multiple shapes. All code using such objects, if they ever see both
>> shapes, will have to handle them both. Even worse, if you have several of
>> these delayed init properties and you end up lazily initializing them in
>> different orders (which seems relatively easy to do), then the internal
>> slot offsets will vary.
>>
>> You don't need to bend over backwards to make things easy for the VMs,
>> but you don't want to be mean to them either. :-)
>>
>> Not to mention that the observable property iteration order will vary.
>>
>> On Mon, Sep 11, 2017 at 7:09 AM, Andrea Giammarchi <mailto:
>> andrea.giammarchi at gmail.com> wrote:
>>
>> Hi Peter.
>>
>> Unless you have a faster way to do lazy property assignment, I think it's
>> irrelevant if internally VMs are not too happy. VMs are there to solve our
>> problems, not vice-versa ;-)
>>
>> Regards
>>
>>
>>
>> On Mon, Sep 11, 2017 at 11:54 AM, peter miller <mailto:
>> fuchsia.groan at virgin.net> wrote:
>> Hi Andrea,
>> ```
>> class CaseLazy {
>>   get bar() {
>>     var value = Math.random();
>>     Object.defineProperty(this, 'bar', {value});
>>     return value;
>>   }
>> }
>> ```
>>
>> Doesn't this count as redefining the shape of the object? Or are the
>> compilers fine with it?
>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> mailto:es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>>
>>
>>
>>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
>
> _______________________________________________
> 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/20170914/e70da9c4/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PastedGraphic-4.png
Type: image/png
Size: 243785 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170914/e70da9c4/attachment-0001.png>


More information about the es-discuss mailing list