Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map optimization : each boiler #1708

Merged
merged 1 commit into from
Jun 27, 2014
Merged

Conversation

megawac
Copy link
Collaborator

@megawac megawac commented Jun 27, 2014

Was playing with this pattern a couple weeks ago and look forward to hearing thoughts from other contributors as we're sacrificing terseness for speed via with boilerplate. I've applied this pattern to some of the other methods in this branch + some thoughts from @jdalton (see comments at the bottom for the relevant jsperf post changes for other functions ).

Figured I would open the conversation as its one of the most used functions in the lib and optimizations here pay dividends. Relevant jsperf below

http://jsperf.com/pr-1689/9

Also, I'm mixed about this change and can agree if we reject this :)

@megawac megawac changed the title Map (major) optimization : each boiler (major) Map optimization : each boiler Jun 27, 2014
@megawac megawac changed the title (major) Map optimization : each boiler Map optimization : each boiler Jun 27, 2014
@davidchambers
Copy link
Contributor

I'm against changes of this nature, because I value the readability of Underscore's source code above performance, provided the performance is acceptable (which it is). Underscore's source code was once a good example of how to write readable JavaScript code using Underscore functions.

That said, since we're already trading readability for performance gains in many places, perhaps there's no reason to stop.

@jdalton
Copy link
Contributor

jdalton commented Jun 27, 2014

❤️

@jdalton
Copy link
Contributor

jdalton commented Jun 27, 2014

The technique @megawac applies to _.map can be applied to other methods too which is nice that it's generic enough to bring improvements to multiple methods. I'll disagree with @davidchambers, I don't find Graeme's technique gross looking, though I'm sure it could be cleaned up.

My implementation goes a different route opting for baseXYZ forms of methods which increases abstraction but works better for my setup (abstract away object/arguments/string iteration & compat concerns). That said, I think Graeme's approach fits where Underscore is at better.

}
var results = Array(length);
for (var index = 0; index < length; index++) {
currentKey = keys ? keys[index] : index;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't test keys in the loop. For optimum performance, we should pull the keys test out and have two loops: one that accesses keys[index] and one that uses index directly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've brought this up with other parts of Underscore in the past & I believe at the time it was proven that the check was negligible. We can check again to validate but avoiding the second loop is a big win for avoiding code dup.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I didn't realise. I'm not super opinionated either way. We'll stick with the simpler style.

@michaelficarra
Copy link
Collaborator

I like this. If anything, I'd say this version is more readable.

_.map = _.collect = function(obj, iterator, context) {
var results = [];
if (obj == null) return results;
_.map = _.collect = function(obj, iterator, context) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks as though there's an extra space at the beginning of this line.

jashkenas added a commit that referenced this pull request Jun 27, 2014
Map optimization : each boiler
@jashkenas jashkenas merged commit 9fa20b4 into jashkenas:master Jun 27, 2014
@megawac megawac deleted the fast-map branch June 27, 2014 17:55
@michaelficarra
Copy link
Collaborator

Cool, looks like we're all in agreement here. @megawac: Want to open a PR to apply this pattern everywhere?

@megawac
Copy link
Collaborator Author

megawac commented Jun 27, 2014

Sure, which functions do you want it for? I'm thinking it makes sense for some+filter.

filter: http://jsperf.com/pr-1689/6
reduce+map: http://jsperf.com/pr-1689/7
some: http://jsperf.com/pr-1689/8

I figured this pattern would be most beneficial for max/min but it didn't work out

@jdalton
Copy link
Contributor

jdalton commented Jun 27, 2014

I figured this pattern would be most beneficial for max/min but it didn't work out

Makes sense because in this case you're doing more work in the array path than the current fast path.
_.min and _.max are divided up by arrays, or arrays/objects+iterator (the baggage the iterator carries with it).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants