Experiment: Function.$case
One of the few things I like about Java is how methods are identified not by their identifier (language collision here, it’d seem) but by their signature. In code:
public static void foo (String bar) {
// do things
}
public static void foo (String[] bar) {
// do things
}
These foo() methods are different in that they accept different types of parameters. In dynamic languages this is not possible, but of course you aren’t limited to one type of parameter.
And yet, I was wondering if there was an elegant way to implement someting comparable in JavaScript. Let’s take the following code, and try to make it more elegant:
function say (value) {
value = value || "";
if (typeof (value) != "string") {
if (value.constructor == Array)
value = value.join("\n");
else {
var result = "";
for(var prop in value)
result += prop + ": " + value[prop] + "\n";
return result;
}
}
alert(value);
}
Hmm, some conditions and specific code in their bodies. It’d almost look like a switch statement, but in JavaScript you can only compare values, not use your own conditions. However, Ruby has a switch mechanism which lets you evaluate conditions:
case
when 1 + 1 == 2
puts "1 + 1 is indeed 2"
when 1 * 1 == 1
puts "1 * 1 is indeed 1"
else
puts "Somebody must have disproved mathematics"
end
Quite elegant. Let’s consider this example:
function say (value) {
value = value || "";
alert (Function.$case (
typeof value == "string", // when
value, // expression
value.constructor == Array, // when
function () { // expression
return value.join("\n");
},
function () { // else
var result = "";
for(var prop in value)
result += prop + ": " + value[prop] + "\n";
return result;
}
));
}
The even attributes (counting from 0) are the conditions. The odd attributes are the expressions, and the last even attribute is the “or else” expression.
I’d say this is (in theory) more elegant, but it looks confusing and requires more code — sounds a bit like Java, actually. And this is what Function.$case() looks like:
Function.$case = function () {
var condition;
for (var i = 0, expr = null; i < arguments.length; i+=2, expr = null) {
condition = arguments[i];
if (i == arguments.length - 1)
expr = condition;
else if (condition === true)
expr = arguments[i + 1];
else if (typeof (condition) == "function" && condition () === true)
expr = arguments[i + 1];
if (typeof (expr) == "function")
return expr ();
else if (expr != null) // To obviate the need for superfluous functions, you can also use a value instead of a function
return expr;
}
}




This is one thing I’ve always liked about Python, where you can just do
def func(*args, **kwargs):And then have the function do different things based on what it finds in its arguments. Django uses that trick in its database API to do all sorts of neat stuff.
James | 19 December 2005, 00:33 | link