Extra functions on Arrays, Maps, etc..
Most of the methods that you listed are either already available in identical form or the same logic can be created with existing methods, I've noted each below
On Thu, Apr 5, 2012 at 11:26 AM, Adam Shannon <adam at ashannon.us> wrote:
Hey all,
Scala has a lot of really handy functions that are on arrays, maps, and a whole range of collections. (It's collection support is a lot bigger than ES's, anyway..) It would be nice to have these included (since we're already including .map, .foreach, etc..).
drop(n) // Drops the first n elements
var a = [1,2,3,4]
undefined
a.slice( 2 ) [ 3, 4 ]
dropRight(n) // Drops the last n elements
var a = [1,2,3,4]
undefined
a.slice( 0, a.length - 2 ) [ 1, 2 ]
filter(fn) // Returns a sub-collection containing the elements that fn(elm) returned true
var a = [1,2,3,4]
undefined
a.filter(function( val ) { return val % 2 === 0; }); [ 2, 4 ]
fold(newColl, fn) // Folds the elements of the original collection into newColl given the results of fn
Similar to reduce?
var a = [1,2,3,4]
undefined
a.reduce(function( cur, prev ) { return cur + prev }, 0);
10
getOrElese // Sugar for (.get === undefined) ? fillerValue : .get partition(fn) // Splits the collection into two sub-collections given the result of fn(elm) being true or false.
These two are easily achieved with library code
take(n) // Take only the first n elements
var a = [1,2,3,4]
undefined
a.slice( 0, 2 ) [ 1, 2 ]
takeRight(n) // Take only the last n elements
var a = [1,2,3,4]
undefined
a.slice( -2 ) [ 3, 4 ]
A.zip(B) // Creates a map from the two collections, treating A as the keys and B as the values
Easily achieved with library code
eg. documentcloud.github.com/underscore/#zip
Of course, there are more than just these that I've listed.
www.scala-lang.org/api/current/scala/collection/Map.html
A simple use case for these are all over in ES6.
var arr = document.getElementsByTagName("a"); var externalElms = arr.filter(function(acc, item) { (/^https?:///).test(item.href) });
Or,
var arr = document.querySelector("div") var divMap = arr.fold(new Map, function(acc, item) { acc.add(item.id, item); });
Nit: You'd still need to convert the NodeList into an array before using any Array methods
On Sat, Apr 7, 2012 at 16:40, Rick Waldron <waldron.rick at gmail.com> wrote:
var arr = document.getElementsByTagName("a"); var externalElms = arr.filter(function(acc, item) { (/^https?:///).test(item.href) });
Or,
var arr = document.querySelector("div") var divMap = arr.fold(new Map, function(acc, item) { acc.add(item.id, item); });
Nit: You'd still need to convert the NodeList into an array before using any Array methods
FYI
DOM4 specs NodeList as an ArrayClass. This will be in ToT WebKit next week. Enjoy :-)
www.w3.org/TR/2012/WD-dom-20120405/#interface-nodelist, dev.w3.org/2006/webapi/WebIDL/#ArrayClass, bugs.webkit.org/show_bug.cgi?id=81573
On Sat, Apr 7, 2012 at 8:24 PM, Erik Arvidsson <erik.arvidsson at gmail.com>wrote:
On Sat, Apr 7, 2012 at 16:40, Rick Waldron <waldron.rick at gmail.com> wrote:
var arr = document.getElementsByTagName("a"); var externalElms = arr.filter(function(acc, item) { (/^https?:///).test(item.href) });
Or,
var arr = document.querySelector("div") var divMap = arr.fold(new Map, function(acc, item) { acc.add(item.id, item); });
Nit: You'd still need to convert the NodeList into an array before using any Array methods
FYI
DOM4 specs NodeList as an ArrayClass. This will be in ToT WebKit next week. Enjoy :-)
www.w3.org/TR/2012/WD-dom-20120405/#interface-nodelist, dev.w3.org/2006/webapi/WebIDL/#ArrayClass, bugs.webkit.org/show_bug.cgi?id=81573
As in, its [[Class]] is "Array" and Array.isArray( nodes ) would evaluate to true?
On Sat, Apr 7, 2012 at 17:28, Rick Waldron <waldron.rick at gmail.com> wrote:
As in, its [[Class]] is "Array" and Array.isArray( nodes ) would evaluate to true?
No, it means that Object.getPrototypeOf(NodeList.prototype) === Array.prototype.
Fortunately all the Array.prototype methods are generic so it all just works.
On Sat, Apr 7, 2012 at 8:31 PM, Erik Arvidsson <erik.arvidsson at gmail.com>wrote:
On Sat, Apr 7, 2012 at 17:28, Rick Waldron <waldron.rick at gmail.com> wrote:
As in, its [[Class]] is "Array" and Array.isArray( nodes ) would evaluate to true?
No, it means that Object.getPrototypeOf(NodeList.prototype) === Array.prototype.
Yes, this part was clear in the links you sent. The question I had was about two things that were not addressed in the links (that I could see, please correct if I missed them)
There will be much confusion on the web if Array.isArray(nodes) returns false, while nodes.push( node ), nodes.slice( 0, 2 ) "just work", especially during periods of transition from DOMx to DOM4.
On Apr 7, 2012, at 20:37, "Rick Waldron" <waldron.rick at gmail.com<mailto:waldron.rick at gmail.com>> wrote:
On Sat, Apr 7, 2012 at 8:31 PM, Erik Arvidsson <erik.arvidsson at gmail.com<mailto:erik.arvidsson at gmail.com>> wrote:
On Sat, Apr 7, 2012 at 17:28, Rick Waldron <waldron.rick at gmail.com<mailto:waldron.rick at gmail.com>> wrote:
As in, its [[Class]] is "Array" and Array.isArray( nodes ) would evaluate to true?
No, it means that Object.getPrototypeOf(NodeList.prototype) === Array.prototype.
Yes, this part was clear in the links you sent. The question I had was about two things that were not addressed in the links (that I could see, please correct if I missed them)
There will be much confusion on the web if Array.isArray(nodes) returns false, while nodes.push( node ), nodes.slice( 0, 2 ) "just work", especially during periods of transition from DOMx to DOM4.
Rick
Fortunately all the Array.prototype methods are generic so it all just works.
-- erik
I think the benefits are so great I'm happy to deal with any confusion.
Although, it sounds like I'll be wanting to go back to instanceof Array
, which is kind of funny.
On Sat, Apr 7, 2012 at 8:41 PM, Domenic Denicola < domenic at domenicdenicola.com> wrote:
On Apr 7, 2012, at 20:37, "Rick Waldron" <waldron.rick at gmail.com> wrote:
On Sat, Apr 7, 2012 at 8:31 PM, Erik Arvidsson <erik.arvidsson at gmail.com
wrote:
On Sat, Apr 7, 2012 at 17:28, Rick Waldron <waldron.rick at gmail.com> wrote:
As in, its [[Class]] is "Array" and Array.isArray( nodes ) would evaluate to true?
No, it means that Object.getPrototypeOf(NodeList.prototype) === Array.prototype.
Yes, this part was clear in the links you sent. The question I had was about two things that were not addressed in the links (that I could see, please correct if I missed them)
There will be much confusion on the web if Array.isArray(nodes) returns false, while nodes.push( node ), nodes.slice( 0, 2 ) "just work", especially during periods of transition from DOMx to DOM4.
Rick
Fortunately all the Array.prototype methods are generic so it all just works.
-- erik
I think the benefits are so great I'm happy to deal with any confusion.
Although, it sounds like I'll be wanting to go back to
instanceof Array
, which is kind of funny.
instanceof Array
is unreliable across contexts (ie. frames) whereas
Object.prototype.toString.call( thing ) === "[object Array]" is
irrefutable... That said, I'm sure there is also plenty of code that that
still expects Object.prototype.toString.call( nodelist ) === "[object
NodeList]" (as unadvisable as that might be)
Erik Arvidsson wrote:
Fortunately all the Array.prototype methods are generic so it all just works.
Except without a new protocol (opt-in, for backward compat) the pure methods all create a new Array instance to return, not a new NodeList. Is that considered potentially problematic?
Allen had an idea based on a standard "private" (unique) name for an opt-in protocol, I think inspired by Smalltalk's 'species'.
I keep finding the frame problem overrated, specially in this case where the case you are passing DOM nodes between frames is ... well, extremely edge?
If NodeList.prototype is instanceof Array then this check is all you need before Array.isArray(nl) but generally speaking I agree is never that easy to understand what's utterable "as if it is" an Array, i.e. live collections as well such getElementsByTagName()
obj instanceof Array || Array.isArray(obj) || ( typeof obj.length === "number" && ~~obj.length === obj.length && (typeof obj != "function" || 0 in obj) ) // latter for functions used as ArrayLike objects
so that Arguments, NodeList, LiveCollections, and Arrays, should all pass this test and we can iterate with common Array.prototype[extras] method
Do you see problems with above checks ? Anything I am not considering ?
br
On 09/Apr/2012 23:55, Brendan Eich wrote:
Erik Arvidsson wrote:
Fortunately all the Array.prototype methods are generic so it all just works.
Except without a new protocol (opt-in, for backward compat) the pure methods all create a new Array instance to return, not a new NodeList. Is that considered potentially problematic?
Sometimes the reverse might be slightly unexpected at first sight. For example mapping over a Set in Scala:
scala> Set("foo", "bar", "bazooka").map(word => word.length) res4: scala.collection.immutable.Set[Int] = Set(3, 7)
One might expect the result to be a collection like [3, 3, 7] whereas the result is a new set in which 3 occurs just once.
Just something to keep in mind.
never mind about functions ... forgot for an instant the length is static so typeof != "function" is enough :-)
On Mon, Apr 9, 2012 at 9:17 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:
I keep finding the frame problem overrated, specially in this case where the case you are passing DOM nodes between frames is ... well, extremely edge?
The frame problem might appear overrated if you imagine that DOM nodes need to be "passed" between frames. But accessing an iframe's DOM nodes is trivial property lookup, theFrame.contentWindow.querySelector(...). That simplicity plus the experience of no significant issues in operating on the iframe content encourages this usage pattern. Mostly devs avoid instanceof, but eventually you end up using instanceof on an array. Nothing noticeable happens when you do, other than your app is broken. Once you track it down you are totally convinced that the browser is busted because the instanceof test fails. You waste a day writing a test case to prove it.
So this iframe problem is rare but hits very hard: you already have a big investment in some code and you have to work hard to figure out what went wrong.
jjb
still, even if NodeList will inherit from Array, the cross frame problem will fail in any case 'cause toString.call(querySelectorAll()) will not produce same as toString.call([]) neither will be instanceof Array or instanceof NodeList
Here the very last fallback to check the length property may become handy ... then we have Safari that consider querySelectorAll() and getElementsByTagName() as typeof "function" ... so, since there's no universal way to understand if that [[Class]] in the other frame is treatable as an Array, I don't see any fully trustable solution that works everywhere ... as developer, we should understand in advance what's iterable as an Array and what is not, specially because we create that frame or theoretically, we should never have access to it and through postMessage, as example, no way to pass an Array that is not recognizable as an Array in the current environment ( passed as string, created once received as Array )
Anyway, here my last "isArrayLike" implementation: gist.github.com/2294934
I should probably consider to check agains toString.call(obj) === nodeListClass then some browser may pass childNodes or getElementsByTagName and implement something different from static NodeList behind the scene ...
Last, but not least, never had this problem in all these years, if you pass nodes between frames ... ask yourself why you need that in first place then control them the way you want, too much magic will miserably fail here and there quite randomly, imho.
P.S. instanceof is simply fast and 99% of the time what's needed for that task
Hey all,
Scala has a lot of really handy functions that are on arrays, maps, and a whole range of collections. (It's collection support is a lot bigger than ES's, anyway..) It would be nice to have these included (since we're already including .map, .foreach, etc..).
drop(n) // Drops the first n elements dropRight(n) // Drops the last n elements filter(fn) // Returns a sub-collection containing the elements that fn(elm) returned true fold(newColl, fn) // Folds the elements of the original collection into newColl given the results of fn getOrElese // Sugar for (.get === undefined) ? fillerValue : .get partition(fn) // Splits the collection into two sub-collections given the result of fn(elm) being true or false. take(n) // Take only the first n elements takeRight(n) // Take only the last n elements A.zip(B) // Creates a map from the two collections, treating A as the keys and B as the values
Of course, there are more than just these that I've listed.
www.scala-lang.org/api/current/scala/collection/Map.html
A simple use case for these are all over in ES6.
var arr = document.getElementsByTagName("a"); var externalElms = arr.filter(function(acc, item) { (/^https?:///).test(item.href) });
Or,
var arr = document.querySelector("div") var divMap = arr.fold(new Map, function(acc, item) { acc.add(item.id, item); });