Hacker News new | ask | show | jobs
by jraph 808 days ago
Say you are dealing with a callback mechanism that takes a function and (only) one value to pass:

   function c(f, v) { ... f(v) ... }

But what you actually need this callback mechanism to call is a function that takes two arguments. No default values.

    function f2(a, b) { ... }
There's no way in js that c is going to call f2 and set its b parameter to something. You can't set v to be a tuple so b will be filled:

    c(f2, "value") => b will be undefined.

    c(f2, [1, 2]) => a will be set to [1, 2].
you need to wrap f2 for this when calling c:

    function wrapf2(b) { return f2("fixed a", b) }
Or you can make c deconstruct v, or use apply:

    function c(f, v) { ... f(...v) ...  }
    function c(f, v) { ... f.apply(null, v) ...  }
but then v always needs to be an array:

    c(f, [1])
    c(f, [1, 2])

    c(f, 1) // fails
This is why in Javascript, multi-arity is different from unary with tuples. JS doesn't have tuples as a primitive / first-class type anyway. In some math notations we don't make the difference, but in most programming languages there's a distinction. Your model where functions are always unary but can take tuples, and (v) is the same as v, is correct (and useful when the distinction doesn't matter and is just annoying to deal with), but doesn't match the way many programming languages actually work. I believe even in most functional programming languages, (v) is different from v, you also said it.

In assembly, different parameters are in fully separate registers or stack entries. Interestingly, you could imagine representing tuples as C structs (that can have only one member) and always pass structs, and passing a one-member struct will actually have the exact same effect as passing a value of a primitive type.