3 ms·
In JavaScript, every function is varadic. The problem is one of contract, not language. Passing varadic functions to higher-order functions without checking w
by politician 14y ago
In JavaScript, every function is varadic. The problem is one of contract, not language. Passing varadic functions to higher-order functions without checking whether the types are compatible will cause a problem in every such language.
The problem is parseInt, not map. Consider:
// using lodash.js (http://lodash.com/)
_.mixin({ args: function () { return _.toArray(arguments); } })
['10','10','10','10'].map(_.compose(parseInt, _.first, _.args)); // #=> [10,10,10,10]
- ricardobeat 14y agoIt's nice to use functional concepts and all, but in practice a simple anonymous function to trim the arguments is clearer and close to zero overhead: ['10','10','10','10'].map(function(n){ return parseInt(n, 10) }) That's one reason to like the conciseness of CoffeeScript, takes the urge to build compositional towers away: ['10','10','10','10'].map (n) -> parseInt(n, 10) Which one would you rather find in your codebase?
- politician 14y agoYes, you can use anonymous functions, and you probably would want to do that in practice. However, I was trying to illustrate the point that JavaScript functions are varadic and function composition was an easy way to drive that point home. EDIT: Also, you raise a really good point in your example which is that when using parseInt you should always specify the base. If I were to modify my example to take that into account it'd get more messy.
- ricardobeat 14y agoI've been using a pair of functions applyRight/Left that fit this case nicely: ['10','10','10','10'].map(applyRight(null, parseInt, [10], 1) The signature is [context, fn, args, slice] where `slice` is the length of arguments to keep from invocation. It's very rare that something warrants using it vs an anonymous function though.
- politician 14y agoThat's interesting, I like how `slice` lets you concat sequences of arguments, but worry about building functions which have too many convenience features. Thought experiment: what if I wanted to pass every other argument?
- ricardobeat 14y agoI imagine you could pass a function function(arg, i){ return i%2 } as the `slice` parameter, but that's going into crazy territory.
- bdr 14y agoHere's what I use: # Adapted from http://autotelicum.github.com/Smooth-CoffeeScript/literate/partial.html F.partial = (func, a...) -> (b...) -> func (for arg in a then arg ?= b.shift())..., b... For example, do `parseInt10 = F.partial(parseInt, undefined, 10)`, then `[].map(parseInt10)` does the right thing.
- adam-f 14y agoNeither. But for the sake of argument, I'd rather see ['10','10','10','10'].map(Number);
- camus 14y ago['10','10','10','10'].map(Number); this is one is correct ['10','10','10','10'].map(String); this one makes sense ['10','10','10','10'].map(Object); i'd like somebody to explain me this one ????????? Javascript is really difficult as soon as one try to do non trivial stuffs.
- ricardobeat 14y agoObject('abc') is the same as new String('abc'), Object(1) the same as new Number(1) - it just calls the .constructor
- iso-8859-1 14y agobut "new Number(x)" is not equal to "Number(x)". So, it's tricky, I guess?
- ville 14y agoNumber(x) performs a type conversion to number, new Number(x) constructs a primitive wrapper object Number: typeof Number("10") //=> "number" typeof new Number("10") //=> "object" The same applies to other wrapper objects, that is, Boolean and String.
- DanWaterworth 14y agoThis is a problem with javascript, functions shouldn't be variadic by default.
- fauigerzigerk 14y agoThe way in which contracts are enforced or not enforced is a language issue though.