It's done with my original Dart version of Shaky. The CoffeScript version is a port of the Dart version.
You can also notice that http://shaky.github.bushong.net/ does not support certain additional features that the post uses, e.g. it does not render curly brace or wavy "~~~~~" break line from the:
+-------+
| 1 +-+
+-------+ |
| 2 | |
+-------+ > N slots reserved for in-object properties
~~~~~~~~~ |
+-------+ |
| N +-+
+-------+
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.
> 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.
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.
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.
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).
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.
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.
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?
> 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.
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)
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.
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).
> 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.
Looks like it's done with Shaky, which has been on HN before: http://shaky.github.bushong.net/
Really neat tool.