Permalink
Browse files

initial draft of removing sparse array workarounds.

  • Loading branch information...
jashkenas committed May 22, 2012
1 parent 6c68465 commit 4e4bc194c0a0e06aa8f7633695ad10030d871a2b
Showing with 4 additions and 40 deletions.
  1. +0 −22 test/arrays.js
  2. +0 −13 test/collections.js
  3. +4 −5 underscore.js
View
@@ -91,28 +91,6 @@ $(document).ready(function() {
var result = (function(){ return _.uniq(arguments); })(1, 2, 1, 3, 1, 4);
equal(result.join(', '), '1, 2, 3, 4', 'works on an arguments object');
var list = [];
list[2] = list[3] = null;
list[8] = 2;
list[10] = 2;
list[11] = 5;
list[14] = 5;
list[16] = 8;
list[19] = 8;
list[26] = list[29] = undefined;
list[33] = "hi";
var result = _.uniq(list, true);
if (0 in [undefined]) {
// According to the JScript ES 3 spec, section 2.1.26, JScript 5.x (IE <=
// 8) treats `undefined` elements in arrays as elisions.
deepEqual(result, [null, 2, 5, 8, undefined, "hi"], "Works with sorted sparse arrays");
equal(result.length, 6, "The resulting array should not be sparse");
} else {
deepEqual(result, [null, 2, 5, 8, "hi"], "Works with sorted sparse arrays where `undefined` elements are elided");
equal(result.length, 5, "The resulting array should not be sparse");
}
});
test("arrays: intersection", function() {
View
@@ -52,9 +52,6 @@ $(document).ready(function() {
var ifnull = _.map(null, function(){});
ok(_.isArray(ifnull) && ifnull.length === 0, 'handles a null properly');
var length = _.map(Array(2), function(v) { return v; }).length;
equal(length, 2, "can preserve a sparse array's length");
});
test('collections: reduce', function() {
@@ -85,11 +82,6 @@ $(document).ready(function() {
ok(_.reduce(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
equal(_.reduce([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
raises(function() { _.reduce([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
var sparseArray = [];
sparseArray[0] = 20;
sparseArray[2] = -5;
equal(_.reduce(sparseArray, function(a, b){ return a - b; }), 25, 'initially-sparse arrays with no memo');
});
test('collections: reduceRight', function() {
@@ -114,11 +106,6 @@ $(document).ready(function() {
equal(_.reduceRight([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
raises(function() { _.reduceRight([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
var sparseArray = [];
sparseArray[0] = 20;
sparseArray[2] = -5;
equal(_.reduceRight(sparseArray, function(a, b){ return a - b; }), -25, 'initially-sparse arrays with no memo');
});
test('collections: detect', function() {
View
@@ -77,7 +77,7 @@
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (var i = 0, l = obj.length; i < l; i++) {
if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
for (var key in obj) {
@@ -97,7 +97,6 @@
each(obj, function(value, index, list) {
results[results.length] = iterator.call(context, value, index, list);
});
if (obj.length === +obj.length) results.length = obj.length;
return results;
};
@@ -323,7 +322,7 @@
// ---------------
// Get the first element of an array. Passing **n** will return the first N
// values in the array. Aliased as `head` and `take`. The **guard** check
// values inthe array. Aliased as `head` and `take`. The **guard** check

This comment has been minimized.

Show comment
Hide comment
@frankdejonge

frankdejonge May 22, 2012

I reckon this is a mistake ;)

@frankdejonge

frankdejonge May 22, 2012

I reckon this is a mistake ;)

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas May 22, 2012

Owner

Quite. Thanks much. 74f86a6

@jashkenas

jashkenas May 22, 2012

Owner

Quite. Thanks much. 74f86a6

// allows it to work with `_.map`.
_.first = _.head = _.take = function(array, n, guard) {
return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
@@ -445,7 +444,7 @@
return array[i] === item ? i : -1;
}
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
return -1;
};
@@ -454,7 +453,7 @@
if (array == null) return -1;
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
var i = array.length;
while (i--) if (i in array && array[i] === item) return i;
while (i--) if (array[i] === item) return i;
return -1;
};

55 comments on commit 4e4bc19

@michaelficarra

This comment has been minimized.

Show comment
Hide comment
@michaelficarra

michaelficarra May 22, 2012

Collaborator

What is this, lodash? I thought underscore was supposed to be conscious of sparse arrays.

Collaborator

michaelficarra replied May 22, 2012

What is this, lodash? I thought underscore was supposed to be conscious of sparse arrays.

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas May 22, 2012

Owner

Underscore was originally made conscious of sparse arrays only because jdalton was being a pest about it. Now that he no longer cares, I'd rather go back to our commonsense implementation. I doubt anyone will care much.

Owner

jashkenas replied May 22, 2012

Underscore was originally made conscious of sparse arrays only because jdalton was being a pest about it. Now that he no longer cares, I'd rather go back to our commonsense implementation. I doubt anyone will care much.

@paulmillr

This comment has been minimized.

Show comment
Hide comment
@paulmillr

paulmillr May 22, 2012

yep, never used sparse arrays except for Array(5).join(' ') in all practice. no real world usage of them.

paulmillr replied May 22, 2012

yep, never used sparse arrays except for Array(5).join(' ') in all practice. no real world usage of them.

@domenic

This comment has been minimized.

Show comment
Hide comment
@domenic

domenic May 23, 2012

+1 for keeping sparse array support, just for consistency with native methods.

domenic replied May 23, 2012

+1 for keeping sparse array support, just for consistency with native methods.

@michaelficarra

This comment has been minimized.

Show comment
Hide comment
@michaelficarra

michaelficarra May 23, 2012

Collaborator

Yeah, I think underscore should support sparse arrays, too.

Collaborator

michaelficarra replied May 23, 2012

Yeah, I think underscore should support sparse arrays, too.

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas May 23, 2012

Owner

@michaelficarra and @domenic -- do you have any examples from your projects where you're relying on this behavior?

Owner

jashkenas replied May 23, 2012

@michaelficarra and @domenic -- do you have any examples from your projects where you're relying on this behavior?

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton May 23, 2012

Contributor

@jashkenas
Following spec is the tax you pay for using native methods and providing a consistent cross-browser experience for fallbacks. The fallbacks in MDN, ES5-Shim, Dojo, jQuery, MooTools, Prototype, and YUI all do this to provide consistent usage.

Contributor

jdalton replied May 23, 2012

@jashkenas
Following spec is the tax you pay for using native methods and providing a consistent cross-browser experience for fallbacks. The fallbacks in MDN, ES5-Shim, Dojo, jQuery, MooTools, Prototype, and YUI all do this to provide consistent usage.

@paulmillr

This comment has been minimized.

Show comment
Hide comment
@paulmillr

paulmillr May 23, 2012

@jdalton why provide a shim for a shitty feature noone uses? I understand consistency argument, but I think it can be easily sacrificed because no_one_uses_sparse_arrays.

paulmillr replied May 23, 2012

@jdalton why provide a shim for a shitty feature noone uses? I understand consistency argument, but I think it can be easily sacrificed because no_one_uses_sparse_arrays.

@braddunbar

This comment has been minimized.

Show comment
Hide comment
@braddunbar

braddunbar May 23, 2012

Collaborator

I don't have a strong opinion on sparse arrays and I agree that they're not often (if ever) relied upon but I think that we should be consistent about providing fallbacks for native functions if that's the direction we're taking. We've often turned down feature requests on the basis that they don't comply with the native forEach, and this seems like a turn in the opposite direction.

Collaborator

braddunbar replied May 23, 2012

I don't have a strong opinion on sparse arrays and I agree that they're not often (if ever) relied upon but I think that we should be consistent about providing fallbacks for native functions if that's the direction we're taking. We've often turned down feature requests on the basis that they don't comply with the native forEach, and this seems like a turn in the opposite direction.

@domenic

This comment has been minimized.

Show comment
Hide comment
@domenic

domenic May 23, 2012

@jashkenas No examples of us depending on underscore for this, but we depend on the native methods' sparse array behavior in cases where we are using arrays as a kind of map which we delete entries from. (This is less horrible than it sounds, I swear.)

domenic replied May 23, 2012

@jashkenas No examples of us depending on underscore for this, but we depend on the native methods' sparse array behavior in cases where we are using arrays as a kind of map which we delete entries from. (This is less horrible than it sounds, I swear.)

@r4j4h

This comment has been minimized.

Show comment
Hide comment
@r4j4h

r4j4h May 23, 2012

Sparse arrays can be very handy when storing a data cache of non-sequential integer ids, say...

objectsCache[32] = some_data;
objectsCache[384] = another_data;
objectsCache[4] = another_data;

normalList = [32,384]
favoritesList = [32,4]

Then you can iterate a list and pull data from the cache. Project I worked on used it to maintain local storage of cached objects, only pulling from server when necessary. The objects could be viewed and sorted in various lists, which were either pregenerated or generated on the fly, and then when needed that list was passed to a renderer to transform/template the respective object(s) into html.

All in all, I just agree with @braddunbar and @jdalton, while you may get to have cleaner and faster code by bypassing small things like that, if you don't model yourself or make it absolutely ing clear that sparse arrays are not supported in the docs and everywhere, then you're creating surprise behavior for uninformed (lots of) users -- and surprise behavior is one of javascript's critics favorite striking points.

(Edit: Oh, and sorry that wasn't an example of using underscore itself for sparse arrays, just one example to show that some people DO use them :x)

r4j4h replied May 23, 2012

Sparse arrays can be very handy when storing a data cache of non-sequential integer ids, say...

objectsCache[32] = some_data;
objectsCache[384] = another_data;
objectsCache[4] = another_data;

normalList = [32,384]
favoritesList = [32,4]

Then you can iterate a list and pull data from the cache. Project I worked on used it to maintain local storage of cached objects, only pulling from server when necessary. The objects could be viewed and sorted in various lists, which were either pregenerated or generated on the fly, and then when needed that list was passed to a renderer to transform/template the respective object(s) into html.

All in all, I just agree with @braddunbar and @jdalton, while you may get to have cleaner and faster code by bypassing small things like that, if you don't model yourself or make it absolutely ing clear that sparse arrays are not supported in the docs and everywhere, then you're creating surprise behavior for uninformed (lots of) users -- and surprise behavior is one of javascript's critics favorite striking points.

(Edit: Oh, and sorry that wasn't an example of using underscore itself for sparse arrays, just one example to show that some people DO use them :x)

@paulmillr

This comment has been minimized.

Show comment
Hide comment
@paulmillr

paulmillr May 23, 2012

@r4j4h in this case you can simply use objects instead of sparse arrays.

paulmillr replied May 23, 2012

@r4j4h in this case you can simply use objects instead of sparse arrays.

@domenic

This comment has been minimized.

Show comment
Hide comment
@domenic

domenic May 23, 2012

@paulmillr There is no Object.prototype.forEach, etc.

domenic replied May 23, 2012

@paulmillr There is no Object.prototype.forEach, etc.

@paulmillr

This comment has been minimized.

Show comment
Hide comment
@paulmillr

paulmillr May 23, 2012

@domenic yep, but there is Object.keys.

Object.keys(obj).forEach()

paulmillr replied May 23, 2012

@domenic yep, but there is Object.keys.

Object.keys(obj).forEach()

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas May 23, 2012

Owner

@r4j4h You're quite right. I've added a note in the docs about not supporting sparse arrays: 36bb762

Owner

jashkenas replied May 23, 2012

@r4j4h You're quite right. I've added a note in the docs about not supporting sparse arrays: 36bb762

@cowboy

This comment has been minimized.

Show comment
Hide comment
@cowboy

cowboy May 23, 2012

I still push for ES5 compliance for any method that uses a native method and fallback.

+1

cowboy replied May 23, 2012

I still push for ES5 compliance for any method that uses a native method and fallback.

+1

@r4j4h

This comment has been minimized.

Show comment
Hide comment
@r4j4h

r4j4h May 23, 2012

@domenic Genius! Though, a downside to Object.keys is it's relatively new and not supported in IE 7 or 8. There are shims, but by using sparse arrays you get cross browser without the shim. Minor pros and cons, use whichever fits best for the job =]

r4j4h replied May 23, 2012

@domenic Genius! Though, a downside to Object.keys is it's relatively new and not supported in IE 7 or 8. There are shims, but by using sparse arrays you get cross browser without the shim. Minor pros and cons, use whichever fits best for the job =]

@mkmcdonald

This comment has been minimized.

Show comment
Hide comment
@mkmcdonald

mkmcdonald May 23, 2012

@jashkenas

Underscore was originally made conscious of sparse arrays only because jdalton was being a pest about it. Now that he no longer cares, I'd rather go back to our commonsense implementation. I doubt anyone will care much.

This is what I like to call "disingenuous browser support". I'm amazed at how many "popular" libraries do it. The moment something ostensibly loses support, code catering specifically to it is razed immediately to cheers of "progress".

As you keep moving goalposts to your own liking, the stability of your code decreases.

mkmcdonald replied May 23, 2012

@jashkenas

Underscore was originally made conscious of sparse arrays only because jdalton was being a pest about it. Now that he no longer cares, I'd rather go back to our commonsense implementation. I doubt anyone will care much.

This is what I like to call "disingenuous browser support". I'm amazed at how many "popular" libraries do it. The moment something ostensibly loses support, code catering specifically to it is razed immediately to cheers of "progress".

As you keep moving goalposts to your own liking, the stability of your code decreases.

@mkmcdonald

This comment has been minimized.

Show comment
Hide comment
@mkmcdonald

mkmcdonald May 23, 2012

@paulmillr

I think it can be easily sacrificed because no_one_uses_sparse_arrays

I use sparse arrays (i.e. manual addition) to maximize browser compatibility when adding document tree nodes to an array. Very old browsers (IE 5 et al.) can err when adding document tree nodes via an array method such as Array.prototype.push. Manual addition is safer.

mkmcdonald replied May 23, 2012

@paulmillr

I think it can be easily sacrificed because no_one_uses_sparse_arrays

I use sparse arrays (i.e. manual addition) to maximize browser compatibility when adding document tree nodes to an array. Very old browsers (IE 5 et al.) can err when adding document tree nodes via an array method such as Array.prototype.push. Manual addition is safer.

@mkmcdonald

This comment has been minimized.

Show comment
Hide comment
@mkmcdonald

mkmcdonald May 23, 2012

@jdalton

Array(4) is sparse, var a=[];a[someIndex]=data; is sparse too.

Nailed it; more people need to listen to this man.

mkmcdonald replied May 23, 2012

@jdalton

Array(4) is sparse, var a=[];a[someIndex]=data; is sparse too.

Nailed it; more people need to listen to this man.

@ajpiano

This comment has been minimized.

Show comment
Hide comment
@ajpiano

ajpiano May 23, 2012

I kind of thought that this was settled with #282, if not earlier, when a bug with _.bind and new was fixed to match spec compliance. It sincerely blows my mind that this same essential argument keeps coming up again and again, and ends up being settled differently. I cannot fathom why anyone thinks it should be the case that the polyfill would have intentionally divergent behaviour from the native method it's filling, and the debugging experience here is absolutely horrendous for the end-developer who runs into a place where underscore behaves different depending on which native methods are available. I'd expect that edge case differences between native and fallback methods would be remedied as soon as possible upon identification, rather than being held up for subjective analysis of the problem that gave rise to the situation (which happened in #282, as well as here).

The tribalism on display here is also distressing - consistently @jdalton's efforts at fighting the good fight on behalf of developers such that they never end up having to encounter problems such as this themselves are portrayed as selfish fits of pique. Sparse arrays aren't some old friend on whose behalf he's lobbying for favours, they're A Thing That Exists™ and should be treated uniformly between native methods and library methods which sometimes delegate off to those native methods, and sometimes don't.

ajpiano replied May 23, 2012

I kind of thought that this was settled with #282, if not earlier, when a bug with _.bind and new was fixed to match spec compliance. It sincerely blows my mind that this same essential argument keeps coming up again and again, and ends up being settled differently. I cannot fathom why anyone thinks it should be the case that the polyfill would have intentionally divergent behaviour from the native method it's filling, and the debugging experience here is absolutely horrendous for the end-developer who runs into a place where underscore behaves different depending on which native methods are available. I'd expect that edge case differences between native and fallback methods would be remedied as soon as possible upon identification, rather than being held up for subjective analysis of the problem that gave rise to the situation (which happened in #282, as well as here).

The tribalism on display here is also distressing - consistently @jdalton's efforts at fighting the good fight on behalf of developers such that they never end up having to encounter problems such as this themselves are portrayed as selfish fits of pique. Sparse arrays aren't some old friend on whose behalf he's lobbying for favours, they're A Thing That Exists™ and should be treated uniformly between native methods and library methods which sometimes delegate off to those native methods, and sometimes don't.

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas May 23, 2012

Owner

As you keep moving goalposts to your own liking, the stability of your code decreases.

Very true, and I deeply apologize for merging the "support" in the first place. It never existed as a wholehearted effort because no one ever had any use cases that relied on it ... and for that reason I feel like it was in an incomplete state for a while.

The tribalism on display here is also distressing.

Whoa buddy, you're reading too much into this commit. It's just that its "better" for Underscore each loops to compile to the straightforward for loop you would have written in its place, and not try to get too fancy. Adding a if (i in array) check in front of each iteration wasn't a great idea.

Owner

jashkenas replied May 23, 2012

As you keep moving goalposts to your own liking, the stability of your code decreases.

Very true, and I deeply apologize for merging the "support" in the first place. It never existed as a wholehearted effort because no one ever had any use cases that relied on it ... and for that reason I feel like it was in an incomplete state for a while.

The tribalism on display here is also distressing.

Whoa buddy, you're reading too much into this commit. It's just that its "better" for Underscore each loops to compile to the straightforward for loop you would have written in its place, and not try to get too fancy. Adding a if (i in array) check in front of each iteration wasn't a great idea.

@braddunbar

This comment has been minimized.

Show comment
Hide comment
@braddunbar

braddunbar May 24, 2012

Collaborator

It's just that its "better" for Underscore each loops to compile to the straightforward for loop you would have written in its place, and not try to get too fancy.

Regardless of sparse array support, each doesn't always use a straightforward for loop.

Adding a if (i in array) check in front of each iteration wasn't a great idea.

Would you mind elaborating a bit? Are you referring to performance considerations, the correctness of the implementation, or the usage patterns regarding sparse arrays?

Collaborator

braddunbar replied May 24, 2012

It's just that its "better" for Underscore each loops to compile to the straightforward for loop you would have written in its place, and not try to get too fancy.

Regardless of sparse array support, each doesn't always use a straightforward for loop.

Adding a if (i in array) check in front of each iteration wasn't a great idea.

Would you mind elaborating a bit? Are you referring to performance considerations, the correctness of the implementation, or the usage patterns regarding sparse arrays?

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas May 24, 2012

Owner

Would you mind elaborating a bit? Are you referring to performance
considerations, the correctness of the implementation, or the usage
patterns regarding sparse arrays?

Sure thing:

  • When you use an _.each, what you want as a user is the native forEach, if available, falling back to a "regular" for loop.
  • Performance of the fallback implementation is important, because it's your limiting factor: it kicks in for the slowest browsers.
  • An extra in check for each iteration is fairly expensive, even when you're calling a function for each iteration.
  • I've rarely heard of a real-world use case for sparse arrays that wouldn't be better handled by using an object, especially where iteration is concerned. You want to iterate sparse arrays and objects in JS with for key in obj, not with an inefficient for loop that checks every index.
Owner

jashkenas replied May 24, 2012

Would you mind elaborating a bit? Are you referring to performance
considerations, the correctness of the implementation, or the usage
patterns regarding sparse arrays?

Sure thing:

  • When you use an _.each, what you want as a user is the native forEach, if available, falling back to a "regular" for loop.
  • Performance of the fallback implementation is important, because it's your limiting factor: it kicks in for the slowest browsers.
  • An extra in check for each iteration is fairly expensive, even when you're calling a function for each iteration.
  • I've rarely heard of a real-world use case for sparse arrays that wouldn't be better handled by using an object, especially where iteration is concerned. You want to iterate sparse arrays and objects in JS with for key in obj, not with an inefficient for loop that checks every index.
@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton May 24, 2012

Contributor

You want to iterate sparse arrays and objects in JS with for key in obj

You just advocated for-in over arrays?

Contributor

jdalton replied May 24, 2012

You want to iterate sparse arrays and objects in JS with for key in obj

You just advocated for-in over arrays?

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas May 24, 2012

Owner

You just advocated for-in over arrays lol.

Yes. For "sparse arrays" being treated as objects, I absolutely did.

http://jsperf.com/sparse-iteration

And that's just with low numbers. If your array is truly sparse, and you're plotting values over a large domain, it gets even more silly to use a for loop with an in check at every index.

Owner

jashkenas replied May 24, 2012

You just advocated for-in over arrays lol.

Yes. For "sparse arrays" being treated as objects, I absolutely did.

http://jsperf.com/sparse-iteration

And that's just with low numbers. If your array is truly sparse, and you're plotting values over a large domain, it gets even more silly to use a for loop with an in check at every index.

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton May 24, 2012

Contributor

A for-in loop won't guarantee property iteration order and they'll iterate over anything added to the Array.prototype, e.g. any shim on the Array.prototype.

Contributor

jdalton replied May 24, 2012

A for-in loop won't guarantee property iteration order and they'll iterate over anything added to the Array.prototype, e.g. any shim on the Array.prototype.

@michaelficarra

This comment has been minimized.

Show comment
Hide comment
@michaelficarra

michaelficarra May 24, 2012

Collaborator

And don't forget about the non-enumerable properties that you'd miss.

Collaborator

michaelficarra replied May 24, 2012

And don't forget about the non-enumerable properties that you'd miss.

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton May 24, 2012

Contributor

@jashkenas
Performance has been used as an excuse to cut cross-browser consistency and now Underscore is behind PrototypeJS, and all other popular JS libs for that matter, in terms of cross-browser consistency.

Underscore may be slow in areas but cross-browser consistency is not the bottleneck, it's poor design decisions. Other alternatives have proven that you can be cross-browser consistent, fixing iteration bugs in IE, Firefox, Safari, and Opera, and still be fast.

As browsers progress the need for a lot of this sugar will disappear because devs in ES5 compatible environments will lean towards native methods. So Underscore's BIG draw is that it should provide these features for older browsers in a consistent way. Cutting consistency is defeating a big reason to use Underscore.

Contributor

jdalton replied May 24, 2012

@jashkenas
Performance has been used as an excuse to cut cross-browser consistency and now Underscore is behind PrototypeJS, and all other popular JS libs for that matter, in terms of cross-browser consistency.

Underscore may be slow in areas but cross-browser consistency is not the bottleneck, it's poor design decisions. Other alternatives have proven that you can be cross-browser consistent, fixing iteration bugs in IE, Firefox, Safari, and Opera, and still be fast.

As browsers progress the need for a lot of this sugar will disappear because devs in ES5 compatible environments will lean towards native methods. So Underscore's BIG draw is that it should provide these features for older browsers in a consistent way. Cutting consistency is defeating a big reason to use Underscore.

@michaelficarra

This comment has been minimized.

Show comment
Hide comment
@michaelficarra

michaelficarra May 24, 2012

Collaborator

it's poor design decisions

You should enumerate these. I believe you're referring to underscore defining its functions in terms of other underscore functions rather than inlining the code.

On the rest of your comment, I agree.

Collaborator

michaelficarra replied May 24, 2012

it's poor design decisions

You should enumerate these. I believe you're referring to underscore defining its functions in terms of other underscore functions rather than inlining the code.

On the rest of your comment, I agree.

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas May 24, 2012

Owner

@jdalton buddy, be careful -- you're starting to sound a lot like David Mark here.

By all means, please use Lo-Dash if you'd rather depend on a codebase like this: https://github.com/bestiejs/lodash/blob/master/lodash.js#L215-341 ... instead of depending on the native forEach implementation. But please stop commenting about it on Underscore issues and commits. It wasn't helpful in the past, and it's not helpful now.

Owner

jashkenas replied May 24, 2012

@jdalton buddy, be careful -- you're starting to sound a lot like David Mark here.

By all means, please use Lo-Dash if you'd rather depend on a codebase like this: https://github.com/bestiejs/lodash/blob/master/lodash.js#L215-341 ... instead of depending on the native forEach implementation. But please stop commenting about it on Underscore issues and commits. It wasn't helpful in the past, and it's not helpful now.

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton May 24, 2012

Contributor

@michaelficarra

You should enumerate these. I believe you're referring to underscore defining its functions in terms of other underscore functions rather than inlining the code.

Yes, it's things like relying too heavily on its own methods and slower ES5 methods instead of simple for-loops.
It's a balance and currently Underscore is too heavy on its own/slower-ES5 API.

@jashkenas

buddy, be careful -- you're starting to sound a lot like David Mark here.

I think I've been pretty respectful all things considered.

if you'd rather depend on a codebase like this [...] ... instead of depending on the native forEach implementation.

That's the pre-build version and method compilation is only used in the compat build. It's awesome because it addresses xbrowser array/object issues in _.forEach as well as _.contains, _.every, _.filter, _.find, _.map, _.pluck, _.reduce, _.reduceRight, _.reject, _.some, _.values, _.defaults, _.extend, _.functions, _.isEmpty, _.keys, _.size, & _.toArray, plus gets minified+inlined 😀


Update: Lo-Dash v3.0.0-pre no longer uses method compilation.

Contributor

jdalton replied May 24, 2012

@michaelficarra

You should enumerate these. I believe you're referring to underscore defining its functions in terms of other underscore functions rather than inlining the code.

Yes, it's things like relying too heavily on its own methods and slower ES5 methods instead of simple for-loops.
It's a balance and currently Underscore is too heavy on its own/slower-ES5 API.

@jashkenas

buddy, be careful -- you're starting to sound a lot like David Mark here.

I think I've been pretty respectful all things considered.

if you'd rather depend on a codebase like this [...] ... instead of depending on the native forEach implementation.

That's the pre-build version and method compilation is only used in the compat build. It's awesome because it addresses xbrowser array/object issues in _.forEach as well as _.contains, _.every, _.filter, _.find, _.map, _.pluck, _.reduce, _.reduceRight, _.reject, _.some, _.values, _.defaults, _.extend, _.functions, _.isEmpty, _.keys, _.size, & _.toArray, plus gets minified+inlined 😀


Update: Lo-Dash v3.0.0-pre no longer uses method compilation.

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas May 24, 2012

Owner

Fantastic. Then please respect my request and stop commenting on @documentcloud projects, starting today. We'll get along just fine -- I promise.

Owner

jashkenas replied May 24, 2012

Fantastic. Then please respect my request and stop commenting on @documentcloud projects, starting today. We'll get along just fine -- I promise.

@ryantenney

This comment has been minimized.

Show comment
Hide comment
@ryantenney

ryantenney May 24, 2012

Contributor

All due respect, but I like having @jdalton as the "Loyal Opposition". The issues I see him raise on this project typically deserve attention.

Contributor

ryantenney replied May 24, 2012

All due respect, but I like having @jdalton as the "Loyal Opposition". The issues I see him raise on this project typically deserve attention.

@benatkin

This comment has been minimized.

Show comment
Hide comment
@benatkin

benatkin May 24, 2012

@ryantenney Individual people are important to software projects, but the list of the individual people a project can't do without is usually pretty low. If someone's knowingly and willingly irritating the creator of a project, I think the project is probably better off without them.

I usually want defects in software to be caught early, even if them breaking is going to cause an issue with the site, and that includes using sparse arrays non-judiciously. So to me it's actually a feature that Underscore won't support sparse arrays, because if I had code that used them, chances are it would break something else.

benatkin replied May 24, 2012

@ryantenney Individual people are important to software projects, but the list of the individual people a project can't do without is usually pretty low. If someone's knowingly and willingly irritating the creator of a project, I think the project is probably better off without them.

I usually want defects in software to be caught early, even if them breaking is going to cause an issue with the site, and that includes using sparse arrays non-judiciously. So to me it's actually a feature that Underscore won't support sparse arrays, because if I had code that used them, chances are it would break something else.

@braddunbar

This comment has been minimized.

Show comment
Hide comment
@braddunbar

braddunbar May 24, 2012

Collaborator

So to me it's actually a feature that Underscore won't support sparse arrays, because if I had code that used them, chances are it would break something else.

Just to be clear, sparse arrays will still behave as per usual and give you no warnings in environments that include a native forEach.

Collaborator

braddunbar replied May 24, 2012

So to me it's actually a feature that Underscore won't support sparse arrays, because if I had code that used them, chances are it would break something else.

Just to be clear, sparse arrays will still behave as per usual and give you no warnings in environments that include a native forEach.

@medikoo

This comment has been minimized.

Show comment
Hide comment
@medikoo

medikoo May 25, 2012

@jdalton Do you have any example of a real world project (e.g. based on Backbone) that noticeably gained in performance after replacing underscore with Lo-Dash?

To me Lo-Dash looks as great example of optimization anti-pattern (premature optimization is talking all the way), brings more mess than it really helps.

medikoo replied May 25, 2012

@jdalton Do you have any example of a real world project (e.g. based on Backbone) that noticeably gained in performance after replacing underscore with Lo-Dash?

To me Lo-Dash looks as great example of optimization anti-pattern (premature optimization is talking all the way), brings more mess than it really helps.

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton May 25, 2012

Contributor

Do you have any example of a real world project (e.g. based on Backbone) that noticeably gained in performance

Yeah there are-lots-of-examples.

great example of optimization anti-pattern (premature optimization is talking all the way), brings more mess than it really helps.

Naw, I don't promote premature/micro-optimizations.
These optimizations allow addressing cross browser bugs w/o worrying about the performance impact as it's offset in other areas.

Contributor

jdalton replied May 25, 2012

Do you have any example of a real world project (e.g. based on Backbone) that noticeably gained in performance

Yeah there are-lots-of-examples.

great example of optimization anti-pattern (premature optimization is talking all the way), brings more mess than it really helps.

Naw, I don't promote premature/micro-optimizations.
These optimizations allow addressing cross browser bugs w/o worrying about the performance impact as it's offset in other areas.

@medikoo

This comment has been minimized.

Show comment
Hide comment
@medikoo

medikoo May 25, 2012

@jdalton sorry for being maybe too harsh. I just doubt that underscore can be main bottleneck in average web application. Let us know when you will have examples of projects that confirm necessity of your optimizations.

medikoo replied May 25, 2012

@jdalton sorry for being maybe too harsh. I just doubt that underscore can be main bottleneck in average web application. Let us know when you will have examples of projects that confirm necessity of your optimizations.

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton May 25, 2012

Contributor

You're missing a point in my last comment. Underscore is bailing on cross-browser consistency and bug fixes because of concern over performance penalties / file bloat and...

These optimizations allow addressing xbrowser bugs w/o worrying about the performance impact as it's offset in other areas.

Contributor

jdalton replied May 25, 2012

You're missing a point in my last comment. Underscore is bailing on cross-browser consistency and bug fixes because of concern over performance penalties / file bloat and...

These optimizations allow addressing xbrowser bugs w/o worrying about the performance impact as it's offset in other areas.

@medikoo

This comment has been minimized.

Show comment
Hide comment
@medikoo

medikoo May 25, 2012

@jdalton indeed, in the name of cross-browser consistency such project makes more sense.

medikoo replied May 25, 2012

@jdalton indeed, in the name of cross-browser consistency such project makes more sense.

@robertlagrant

This comment has been minimized.

Show comment
Hide comment
@robertlagrant

robertlagrant Nov 14, 2013

@medikoo Agreed, and the project owner seems pretty easily riled. If LoDash is more consistent and it's faster, then he should be taking this guy's advice, not resorting to passive-aggressive sniping. Those two properties (consistency and speed) are key. I couldn't care about how the codebase looks; this sort of library exists to be messy, so my code can be clean and fast.

robertlagrant replied Nov 14, 2013

@medikoo Agreed, and the project owner seems pretty easily riled. If LoDash is more consistent and it's faster, then he should be taking this guy's advice, not resorting to passive-aggressive sniping. Those two properties (consistency and speed) are key. I couldn't care about how the codebase looks; this sort of library exists to be messy, so my code can be clean and fast.

@petkaantonov

This comment has been minimized.

Show comment
Hide comment
@petkaantonov

petkaantonov Dec 4, 2013

You don't need an in check in older browsers because they cannot have accessors so you can achieve correct semantics for free:

var item = array[i];

if (item === void 0 && !(i in array)) {
    continue;
}

petkaantonov replied Dec 4, 2013

You don't need an in check in older browsers because they cannot have accessors so you can achieve correct semantics for free:

var item = array[i];

if (item === void 0 && !(i in array)) {
    continue;
}
@San-Jeevan

This comment has been minimized.

Show comment
Hide comment
@San-Jeevan

San-Jeevan Jun 12, 2014

I just read this thread, but I use it sparse arrays like array[ID] all the time my projects but I thought they were hashtable and required O(1) in lookup time but if it just an array taking O(n) then there is no point in using that anymore.

San-Jeevan replied Jun 12, 2014

I just read this thread, but I use it sparse arrays like array[ID] all the time my projects but I thought they were hashtable and required O(1) in lookup time but if it just an array taking O(n) then there is no point in using that anymore.

@petkaantonov

This comment has been minimized.

Show comment
Hide comment
@petkaantonov

petkaantonov Jun 12, 2014

@San-Jeevan arrays have O(1) random access too, with a much smaller constant than hash table even

petkaantonov replied Jun 12, 2014

@San-Jeevan arrays have O(1) random access too, with a much smaller constant than hash table even

@San-Jeevan

This comment has been minimized.

Show comment
Hide comment
@San-Jeevan

San-Jeevan Jun 12, 2014

ok then I wasnt wrong afterall.

San-Jeevan replied Jun 12, 2014

ok then I wasnt wrong afterall.

@SeanCannon

This comment has been minimized.

Show comment
Hide comment
@SeanCannon

SeanCannon replied Aug 11, 2014

tl;dr

@spiritix

This comment has been minimized.

Show comment
Hide comment
@spiritix

spiritix Oct 28, 2016

Funny to read in 2016.

spiritix replied Oct 28, 2016

Funny to read in 2016.

@UnbrandedTech

This comment has been minimized.

Show comment
Hide comment
@UnbrandedTech

UnbrandedTech Mar 1, 2017

@spiritix Funny to read in 2017

UnbrandedTech replied Mar 1, 2017

@spiritix Funny to read in 2017

@sakramentas

This comment has been minimized.

Show comment
Hide comment
@sakramentas

sakramentas Mar 29, 2017

@UnbrandedTech Funny to read here in 2023.

sakramentas replied Mar 29, 2017

@UnbrandedTech Funny to read here in 2023.

@emiglobetrotting

This comment has been minimized.

Show comment
Hide comment
@emiglobetrotting

emiglobetrotting Apr 8, 2017

@sakramentas Funny to read here in 2024.

emiglobetrotting replied Apr 8, 2017

@sakramentas Funny to read here in 2024.

@amielperez

This comment has been minimized.

Show comment
Hide comment
@amielperez

amielperez Aug 25, 2017

Who else got here because of stackexchange? 🤔

amielperez replied Aug 25, 2017

Who else got here because of stackexchange? 🤔

@ZzZombo

This comment has been minimized.

Show comment
Hide comment
@ZzZombo

ZzZombo Dec 24, 2017

@amielperez Me. And holy shit. Gonna replace Underscore by Lodash real quick.

ZzZombo replied Dec 24, 2017

@amielperez Me. And holy shit. Gonna replace Underscore by Lodash real quick.

@chence

This comment has been minimized.

Show comment
Hide comment
@chence

chence Aug 8, 2018

@spiritix @UnbrandedTech Funny to read in 2018.

chence replied Aug 8, 2018

@spiritix @UnbrandedTech Funny to read in 2018.

@robertlagrant

This comment has been minimized.

Show comment
Hide comment
@robertlagrant

robertlagrant replied Aug 8, 2018

@amielperez ya'll welcome :D

Please sign in to comment.