Removing dependency on Prototype

11 views
Skip to first unread message

John Freeman

unread,
Jan 27, 2012, 5:59:02 PM1/27/12
to neonst...@gmail.com, hotdri...@googlegroups.com
Howdy!

I'm sorry I didn't respond earlier. Of course we'd love collaborators!

I think the Prototype dependency issue is a little more complicated. I'm
personally not a fan of littering the code with for-in loops and
hasOwnProperty checks, and performance has not been an issue.
Underscore.js provides some uniform iteration functions that could hold
us over until the next version of JavaScript. As a dependency, it is
much smaller and less invasive than Prototype.

However, Underscore.js provides minimal support for inheritance and
class mixins (IIRC just an "extend" function), which we do use
extensively for our controllers.

I hadn't seen that Google Code started supporting Git. I'll work on
uploading our source this weekend.

Thank you,
John

neonstalwart

unread,
Jan 30, 2012, 1:22:34 PM1/30/12
to hotdri...@googlegroups.com, neonst...@gmail.com
i posted this directly to john - posting here for visibility

ok - looking at the controllers now i see how inheritance will play a bigger role.  maybe something like https://github.com/kriszyp/compose would be suitable.  its only 3kb minified (1kb with gzip).

also, maybe using something like https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js would be a good idea rather than underscore.  by using es5-shim, you make it an "optional" dependency.  for example, if someone knew that they were deploying to an environment that already supported es5, they would not need the shim.  whereas if you use underscore, you always have to include it.

eg:

// works without needing es5-shim if running in an es5 environment
Object.keys(someObj).forEach(function(key) {
     var value = someObj[key];
     process(value);
});

// always needs underscore
_.each(someObj, function (value, key) {
     process(value);
});

both es5-shim and underscore use native implementations when available and comparing minified size, the combination of composejs (3kb) and es5-shim (8kb) are similar to underscore (12kb) except that if someone was deploying to an es5 environment (eg mobile devices) they don't need to include es5-shim so then the 8kb saving could be a significant win for them.

for full disclosure, i'm a committer for dojo and composejs is developed by another dojo committer (kris zyp) and is being discussed as a candidate for replacing dojo.declare in dojo 2.0 and possibly being introduced as an optional alternative to dojo.declare in a release before 2.0

thanks,

ben...

John Freeman

unread,
Jan 30, 2012, 1:48:47 PM1/30/12
to hotdri...@googlegroups.com
On 1/30/2012 12:22 PM, neonstalwart wrote:
> i posted this directly to john - posting here for visibility

Did this not go to the group originally because you weren't a member
yet, or do I need to change some settings to allow CC messages through?

> ok - looking at the controllers now i see how inheritance will play a bigger role. maybe something likehttps://github.com/kriszyp/compose would be suitable. its only 3kb minified (1kb with gzip).

I'll take a look at this when we revisit controllers (probably next week
or later this week if I work fast enough).

> Object.keys(someObj).forEach(function(key) {

Does this work by modifying the Object protoype, like PrototypeJS? Right
now, it appears in my tests that the methods PrototypeJS adds to Arrays
show up in for-in loops, even with a hasOwnProperty check.


Thank you for the information and advice!

- John

neonstalwart

unread,
Jan 30, 2012, 3:53:15 PM1/30/12
to hotdri...@googlegroups.com


On Monday, January 30, 2012 1:48:47 PM UTC-5, jfreeman wrote:
On 1/30/2012 12:22 PM, neonstalwart wrote:
> i posted this directly to john - posting here for visibility

Did this not go to the group originally because you weren't a member
yet, or do I need to change some settings to allow CC messages through?

i hadn't joined the group yet - it probably works fine. 
 
<snip>

Does this work by modifying the Object protoype, like PrototypeJS? Right
now, it appears in my tests that the methods PrototypeJS adds to Arrays
show up in for-in loops, even with a hasOwnProperty check.

yes es5-shim modifies the native prototypes.  however, http://jsfiddle.net/neonstalwart/stGw6/ shows that these extra methods don't show up when using hasOwnProperty checks.  if leaving the native prototypes completely untouched is the highest priority then a library like underscore would be the choice to make - although given my bias i'd suggest dojo :)

in the past, apart from changing for-in loops, part of the issue with libraries touching the native prototypes is that the implementations provided have been faulty.  this is why es5-shim emphasizes its test coverage that shows compliance with es5.  also, the ability to opt-out of es5-shim for those that know they don't need it can be a fairly big selling point in my opinion.

code written without hasOwnProperty checks will still break with es5-shim so i guess you have to weigh up the benefit of being able to opt-out of es5-shim with the cost of telling users that they need to use hasOwnProperty checks.  it seems to be increasingly acceptable to say that code without hasOwnProperty checks is "broken" but you (hotdrink) would need to decide if that's an acceptable position to take for your users.

ben...
 

John Freeman

unread,
Jan 31, 2012, 11:59:52 AM1/31/12
to hotdri...@googlegroups.com
On 1/30/12 12:22 PM, neonstalwart wrote:
> Object.keys(someObj).forEach(function(key) {

This results in two loops, correct?

I'm not too hip with the JavaScript community. Is this how everyone does
it these days, or is it more popular to use a hand-written for-in loop
with a hasOwnProperty check?

What I would give for a clean, concise, efficient for-loop...

- John

John Freeman

unread,
Jan 31, 2012, 12:07:32 PM1/31/12
to hotdri...@googlegroups.com
On 1/31/12 10:59 AM, John Freeman wrote:
> On 1/30/12 12:22 PM, neonstalwart wrote:
>> Object.keys(someObj).forEach(function(key) {

This creates an anonymous function each time this loop comes up. Is that
efficient in modern engines yet? I know I did the same thing with
Prototype, but if I'm going to be refactoring loops (and setting new
habits), I figure I should try to find the best option.

- John

neonstalwart

unread,
Jan 31, 2012, 1:11:58 PM1/31/12
to hotdri...@googlegroups.com
yes - it's 2 loops (kind of).   http://jsperf.com/looping-through-array-or-obect-for-vs-foreach shows that where browsers support this natively, its faster than a for-in loop.  however, the browsers that don't support this natively (IE < 9, see  http://kangax.github.com/es5-compat-table/  for a compatibility table) are where performance is more critical.  the question becomes how much do those older IE browsers matter to hotdrink?  if they are critical then for-in with hasOwnProperty check is maybe the best balance across all browsers.  

by writing inline for-in loops you'll likely have no need for underscore or es5-shim.  even if you preferred to write your own util function that was able to iterate objects or arrays then you could still avoid a dependency on an external library but you then have the overhead of making a function call for each iteration.  modern engines are fairly good at optimizing these anonymous functions so again the issue becomes a matter of how relevant older browsers are to hotdrink.

my opinion is that hotdrink can probably afford to lean towards more modern browsers and it shouldn't be an issue to anyone wanting to adopt this library.  if you already had a large user base then it might be a different story.

ideally, you should add some performance tests (maybe they already exist) so that you can profile these changes.  find out what kind of performance you're getting now, and then compare with various options.  i'd suggest just coming up with some reasonably intensive test that focuses on a specific component (eg the solver) and then we test the performance after converting the parts of the library that are most critical to the performance of that test.  once we figure out which approach seems to give the best performance for the more critical components then we convert the whole library to match that approach.

i'd say there are 4 main options to test
 - current implementation
 - Object.keys( ... ).forEach( ... )
 - inline for-in with hasOwnProperty
 - helper function that iterates over arrays or objects ie util.each(arrOrObj, function (value, indexOrKey, arrOrObj) { ... }, optionalContext);

an optional 5th test would be to use underscore and profile _.each but i think the 4th option above covers this without a need to depend on underscore.

if you have a performance test, i don't mind to work on implementing one (or more) of the options so we can profile it.  with all of these changes, you'd no longer be using set and get and i think that will help improve performance as well.  http://code.google.com/chrome/devtools/docs/cpu-profiling.html might be a useful reference if you're not already familiar with it.

John Freeman

unread,
Jan 31, 2012, 1:39:58 PM1/31/12
to hotdri...@googlegroups.com
On 1/31/12 12:11 PM, neonstalwart wrote:
> http://jsperf.com/looping-through-array-or-obect-for-vs-foreach shows
> that where browsers support this natively, its faster than a for-in
> loop.

Thank you for linking this. I think this is enough evidence for me to
proceed. Performance hasn't been a problem with HotDrink in our
experience, but I wanted to know the state of the art.

> modern engines are fairly
> good at optimizing these anonymous functions

That is good to hear.

> my opinion is that hotdrink can probably afford to lean towards more
> modern browsers and it shouldn't be an issue to anyone wanting to adopt
> this library. if you already had a large user base then it might be a
> different story.

I agree. Legacy browsers are not a priority for HotDrink.

> ideally, you should add some performance tests (maybe they already
> exist) so that you can profile these changes.

This is definitely an ideal. HotDrink doesn't have any right now. In our
manual testing experience, performance has not been an issue, so we
haven't invested the time and effort for a performance testsuite.

Our biggest hurdle is devising large test cases based on real
applications. In our experience, large multi-way constraint systems just
do not appear in real-world interfaces. Even small systems are rare. I
speculate that factors may include lack of support in existing
frameworks, complexity, or habit (developers used to thinking in terms
of single-way constraint systems).

Thank you,
John

John Freeman

unread,
Jan 31, 2012, 1:51:28 PM1/31/12
to hotdri...@googlegroups.com
Any idea why there is no forEach for objects? I would love for the
iteration function to get a parameter for the property's value instead
of having to look it up.

- John

neonstalwart

unread,
Jan 31, 2012, 2:01:07 PM1/31/12
to hotdri...@googlegroups.com
i'm not sure why that is.  i've wondered it myself before but i can't think of why.  maybe its more expensive to get the value and so getting just the key is the lowest common denominator and then only those who need the value have to pay the price for it???

ben...
Reply all
Reply to author
Forward
0 new messages