
New Fn() vs. Object.create(P) - tambourine_man
http://mrale.ph/blog/2014/07/30/constructor-vs-objectcreate.html
======
TazeTSchnitzel
I like how this page uses ASCII diagrams converted into fancy graphical ones
on-the-fly!

Looks like it's done with Shaky, which has been on HN before:
[http://shaky.github.bushong.net/](http://shaky.github.bushong.net/)

Really neat tool.

~~~
leeoniya
I'd say somewhat impractical since one can scribble those diagrams in MSPaint
much faster than making them in ASCII first. I'd actually find the opposite
direction much more useful.

[http://asciiflow.com/](http://asciiflow.com/) might be helpful otherwise.

~~~
magicalist
> _I 'd say somewhat impractical since one can scribble those diagrams in
> MSPaint much faster than making them in ASCII first_

...until you want to tweak the layout of an almost completed diagram slightly,
and now you hate life.

For a particular type of diagram (notably there are very few options, and the
more options you add the closer you are to needing a full diagram editing
program (like asciiflow) instead of a text file) this is a great productivity
booster.

------
TheAceOfHearts
Might wanna add 2014 to the title?

Now that we have ES2015, I wonder if there's any performance difference
between using a function and a class, even though class is "just sugar" over
prototypes.

~~~
mraleph
ES2015 class does not provide you with a way to declare instance fields. You
still create them imperatively in the constructor. Which means for the
purposes of the post ES2015 classes are not different from standalone
constructor functions - as VM still has to figure out optimal layout
dynamically.

------
TazeTSchnitzel
This structure looked familiar to me:

    
    
      +-------+
      |   *---+-> hidden class (aka map)
      +-------+
      |   *---+-> out-of-object properties storage
      +-------+
      |   *---+-> elements storage
      +-------+
      |   1   +-+
      +-------+ |
      |   2   | |
      +-------+  > N slots reserved for in-object properties
      ~~~~~~~~~ |
      +-------+ |
      |   N   +-+
      +-------+
    

That's because it's very close to PHP 7's implementation of objects (PHP has
"traditional" class-based OOP):

    
    
      zend_object:
      +-------------+-------------+------------+-----------------------------------------+
      | gc_info     | flags       | IS_OBJECT  | refcount (32-bit)                       |
      +-------------+-------------+------------+-----------------------------------------+
      | UNUSED (32-bit)                        | handle (32-bit) FIXME                   |
      +----------------------------------------+-----------------------------------------+
      | ce - pointer to zend_class_entry (64-bit or 32-bit)                              |
      +----------------------------------------------------------------------------------+
      | handlers - pointer to object handlers (64-bit or 32-bit)                         |
      +----------------------------------------------------------------------------------+
      | properties - pointer to HashTable of dynamic properties (64-bit or 32-bit)       |
      +----------------------------------------------------------------------------------+
      | guards - pointer to HashTable used for recursion protection (64-bit or 32-bit)   |
      +----------------------------------------------------------------------------------+
      | properties_table[0] - embedded cell of the first declared property (128-bit)     |
      +----------------------------------------------------------------------------------+
      | ...                                                                              |
      +----------------------------------------------------------------------------------+
      | properties_table[N] - embedded cell of the last declared property (128-bit)      |
      +----------------------------------------------------------------------------------+
      | optional user data of internal classes (variable size)                           |
      +----------------------------------------------------------------------------------+
       63         48 47         40 39        32 31                                      0
    

(source: [https://wiki.php.net/phpng-
int#is_object](https://wiki.php.net/phpng-int#is_object))

PHP 7 objects contain N slots for properties defined in the class, plus a
hashtable for any additional properties, just like V8 objects.

I guess it's an obvious way to design it.

~~~
mraleph
> I guess it's an obvious way to design it.

It's an obvious way to design it... if you start with explicitly declared
properties in your language.

For JavaScript a state-of-art for a long time was more like this:

    
    
      +-------+
      |   *---+-> hashtable for properties
      +-------+
      |       |
      ~~~~~~~~~ various metadata (e.g. prototype chain)
      ~~~~~~~~~
      |       | 
      +-------+
    

all properties mixed together, all stored in a hash table, etc.

The non-obvious thing to design here is how you escape from the realm of
hashtables into the realm of something both more compact and faster to work
with (given certain statistical assumptions about the properties of the code).

~~~
evincarofautumn
Moreover, if you’re doing the naïve thing, hashtables _per se_ aren’t even
particularly good for object properties—most objects are small, so an RB-tree
or even linear search performs nicely.

------
jtwebman
What if you just did it more of the functional way. Have an object for state
that is passed in for each function. Then Object.create isn't so bad. Just an
idea as I found this pattern easier to maintain though I still use new.

------
swang
Hi mraleph, if you're still reading this thread, how are you getting these
result?

Is worrying about this for normal web apps just a micro-optimization or can
you see instances where this would affect an application's speed
significantly?

~~~
mraleph
> Is worrying about this for normal web apps just a micro-optimization or can
> you see instances where this would affect an application's speed
> significantly?

I don't think there is such thing as an average web application so things must
be decided on the case-by-case basis.

In general if creation/usage of some "class" of objects is on the very hot
path - then their layout can affect performance of the hot path. In this case
constructor might be preferable for the reasons outlined in the post (faster
construction, one less indirection for the property access). However the
decision must be made only after deep investigation.

~~~
senotrusov
Trying to understand the described matter I created some simple code to
benchmark different cases.

Probably I got something wrong, but setting properties inside the constructor
function (prop-benchmark-b.js) are almost 6 times slower that setting them
outside of it (prop-benchmark-a.js)

[https://gist.github.com/senotrusov/597514c773089b6989c6](https://gist.github.com/senotrusov/597514c773089b6989c6)

What do you think, why I got such a different numbers?

Thank you!

~~~
mraleph
There is a bug in your code:

    
    
        var o = new F(i, i, i, i, i, i, i, i, i, i, z)
        z = o
        // ... skipped 
        o.z = z
    

This makes o.z = o, so only the last object survives. When you use constructor
you actually link all of them together - which means there is more garbage
around - GCs are more expensive.

If you fix this bug, e.g. by doing

    
    
        var o = new F(i, i, i, i, i, i, i, i, i, i, z)
        o.z = z
        z = o
    

you actually OOM in prop-benchmark-a.js case because object there is less
compact than one created by constructor. Just as the post predicts.

~~~
senotrusov
Thank you!

I was lucky to not hit OOM and I've got 5.648s for setting properties outside
of the constructor and 3.680s for setting them inside of the constructor, so
just as the post predicts.

At the same time, if I'm trying to simplify the test case and set only numeric
values and not object ones, I've got nearly the same results: 3.953s and
3.922s for 10x more iterations (prop-benchmark-f.js and prop-benchmark-g.js).

(node 4.0.0 on Mac OS)

~~~
mraleph
> At the same time, if I'm trying to simplify the test case and set only
> numeric values and not object ones, I've got nearly the same results: 3.953s
> and 3.922s for 10x more iterations (prop-benchmark-f.js and prop-
> benchmark-g.js).

Well, the secret here is that even if you have an empty constructor V8 still
initially gives enough slack to you object for 10 in-object properties, and by
coincidence you have precisely 10 properties.

Just add one more and observe the difference.

