Skip to content

Comment on Stupid Languages

Comments

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]

It'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?

Yes, 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.

I'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.

That'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?

Here'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.

I imagine you could pass a function

   function(arg, i){ return i%2 }
as the `slice` parameter, but that's going into crazy territory.

Neither.

But for the sake of argument, I'd rather see

  ['10','10','10','10'].map(Number);

['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.

Object('abc') is the same as new String('abc'), Object(1) the same as new Number(1) - it just calls the .constructor

but "new Number(x)" is not equal to "Number(x)". So, it's tricky, I guess?

Number(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.

This is a problem with javascript, functions shouldn't be variadic by default.

The way in which contracts are enforced or not enforced is a language issue though.

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.