In languages derived from C, including JavaScript, they use `switch` rather than `case`, like so:
; Arc
(case x
"foo" ...
"bar" ...)
// JavaScript
switch (x) {
case "foo":
...
break;
case "bar":
...
break;
}
As you can see, switch blocks are atrocious, especially because they require a break; statement or they'll fallthrough. So instead of using switch, some developers prefer if/else chains:
if (x === "foo") {
...
} else if (x === "bar") {
...
}
Which, as you can see, are less verbose. Arc gets it right, JavaScript doesn't.
I'm going to argue that you're comparing apples to oranges to pears.
Arc and Javascript case functions are not expected to do the same thing. JS does not allow expressions for input arguments while Arc can. And that break; statement is a feature that some would say Arc lacks. ie, what if you want your case statement to fall through? - now Javascript is golden and one could say Arc is lacking.
I also don't believe developers, generally speaking, prefer if/else chains over switch/case statements as they are different tools intended for different purposes.
They both are not perfect, both are missing features that the other could benefit from.
I think Clojure got it right having it all: case + cond + condp.
On the contrary, switch should not have a break statement! It should have a fallthru; or continue; statement. Why make the common case difficult? This should be uncontroversial... it's been well established that switch's design is poor, and they should have made it explicit fallthru (like with a continue statement) rather than implicit.
As for Arc "lacking" fallthru... can't you implement that with continuations? That would be the equivalent of explicit fallthru.
---
My point was that switch statements are so atrocious that even in the situations that they were intended for, some developers still prefer if/else chains because they're shorter and more readable.
I think that's because the above semantics correspond more directly to assembly language, which I imagine was done because "switch" was defined back when that was either important or just not seen to be bad. (Perhaps I'm just making that up, though.) Here's how a switch statement would look in x64 assembly:
switch:
;put desired thing in rax, let's say
case_1:
cmp rax, val_1
jne case_2 ;jump if not equal
<case 1 code>
case_2:
cmp rax, val_2
jne case_3
<case 2 code>
case_3:
cmp rax, val_2
jne done
<case 3 code>
done:
<whatever>
By default, the machine will just plow through the remaining cases. If you want it to break out after one case, you have to tell it to do so:
switch:
;put desired thing in rax, let's say
case_1:
cmp rax, val_1
jne case_2 ;jump if not equal
<case 1 code>
jmp done ;jump.
case_2:
cmp rax, val_2
jne case_3
<case 2 code>
jmp done
case_3:
cmp rax, val_2
jne done
<case 3 code>
done:
<whatever>
Assembly language is kind of awesome, by the way. And so is the Miller-Rabin primality test. Some disorganized code: http://pastebin.com/raw.php?i=wRyQ2NAx
Fine. That's great and all for C, but I dislike how Java copied C word-for-word, and then JavaScript copied Java. It would have been nice if they had said, "hm... using continue rather than break would make a lot more sense."
It's not a huge deal, and developers can simply avoid switch if they don't like it. My point was merely that "JavaScript's switch sucks, Arc's (case) is awesome."
> JavaScript allows arbitrary expressions in switch statements
That's right... looks like it was the test data I was thinking of, which isn't entirely relevant, given you can accomplish the same thing in the end.
> Why make the common case difficult?
A fall-through could be nicer than many breaks. Trying to think of all the scenarios required to make this usable, i.e., do you need a break to get out of a fall-through? Maybe that's why they just went with break. either way, it's a good idea.
The current behavior for switch is simple: it will continue until it finds a break statement. Thus:
switch (true) {
case true:
console.log(1);
case true:
console.log(2);
case true:
console.log(3);
break;
case true:
console.log(4);
}
...which outputs 1, 2, and 3. If you wanted to have the same behavior using the continue statement, you would use this:
switch (true) {
case true:
console.log(1);
continue;
case true:
console.log(2);
continue;
case true:
console.log(3);
case true:
console.log(4);
}
As far as I know, this would have exactly the same power as using break; but would be much better suited for the very common case of not wanting fallthru. I think it's much more readable, too: makes it very obvious where it falls through. And it's less error prone... no more strange bugs if you accidentally forget to add in a break; statement.
In fact, in my years and years of programming in JavaScript, I have used if/else blocks many many times (some of which could have been switch statements), and only wanted fallthru a handful of times. I think allowing fallthru is fine, but it should be made explicit, rather than implicit.
The only possible argument I can think of in favor of implicit fallthru is using a switch inside a `for` loop:
for (var i = 0; i < array.length; i += 1) {
switch (array[i]) {
case "foo":
continue;
}
}
...but that's actually ridiculous because I'm fairly sure that breaking out of a loop is far more common than continuing. In which case explicit fallthru would be better with loops.
Oh, that makes a bit more sense. Technically speaking, Arc's case expression is sorta like guards, though, in the sense of dispatching to different code depending on a condition. You're right that wart's :case is essentially a super nice version of `case`.
Also, what's wrong with `switch` whining? :P This is a JavaScript forum, right? Oh wait...