This is the first post of a hopeful series dubbed “JavaScript, tip of the week“; I will try to release a tip in some form every week.
I’m young and haven’t been doing this programming thing for very long so the fact that I’ve never had to use a switch-case statement (to my recollection) might not be very impressive; actually you probably see this as a bad thing and you might even be wondering why I haven’t. I can’t really explain why but I seem to have an inherent dislike of things like this:
switch (something) { case 1: doX(); break; case 2: doY(); break; case 3: doN(); break; // And so on... } |
The fictional author of this code obviously doesn’t know enough about JavaScript to make use of its various other constructs, most of them ten times more suited to this situation than an ugly switch statement. It’s not its appearance that truly annoys me though; it’s the knowledge that there are so many easier and more graceful ways of achieving such functionality.
Switch statements are considered as useful when you have a single variable and dependent on its value you want to carry out one of a number of different tasks. Using multiple if-else clauses doesn’t seem appropriate so the switch statement is often called upon to lend a hand. I’m sure most of you are familier with it and have seen it more than once before.
Let’s take the example from above; dependent on the value of something
we run doX
, doY
or doN
. In JavaScript, the same logic can be expressed with a simple lookup table in the form of an object:
var cases = { 1: doX, 2: doY, 3: doN }; if (cases[something]) { cases[something](); } |
Not only is this cleaner but it’s also reusable, modifiable and accessible… All the conditions are saved as part of an object, so if you ever need to recall or change those conditions then it’s as easy as cases[condition]
.
I suspect this covers about 90% of situations where a switch-statement is used; the remaining 10% are probably legitimate uses. Using a lookup table as an alternative to the Switch statement is not new; in fact this is the only way such logic can be expressed in both the Python and Lua languages, both of which have no support for switch statements.
So, my message is the following: do not use switch-case constructs unless absolutely necessary. Why? – Because there are better alternatives; simple as that!
Read more about the “Switch Statement” here: en.wikipedia.org/wiki/Switch_statement.
Thanks for reading! Please share your thoughts with me on Twitter. Have a great day!
Excellent point James. I’d say that about 99% of all switch statements should be done another way. There’s no real reason to use them (other than “that’s what I’ve always done”). They don’t perform better than cascaded if-then-else in almost all cases.
They also break Structured Programming rules and readability: you should be able to see the code flow without reading every line. The nested “break” statements are just glorified “goto” statements, imho.
http://en.wikipedia.org/wiki/Structured_programming
Thanks for the tip, I’ve never used this method before.
And here is an example of code when the use of switch is more appropriate, in my opinion.
Nice, this is a quite smart way to handle switch-cases. Hadn’t thought about it myself. I think the strategy pattern is also a good approach to reducing switches, but it isn’t always applicable
This is obvious, but I thought I would point it out. An else statement after “if (cases[something])” would handle all the default cases.
What would be a better approach if a case goes into the next case (no break statement)?
Andrew, the way you format your switch statements makes it easy to read / understand. That, in my opinion, makes it acceptable.
I guess I was just ranting. My excuse: I was just on a project where there were 100-line switch statements everywhere! (Not 100-case switch statements. There were several cases and dozens of lines of code in each case — and no line separators to make the case and break statements stand out.)
If a switch statement makes the code clearer than an if-else, then I am fine. Structured Programming rules are just guidelines to make code more understandable, right?
But I still hate when there are multiple return paths from a function. Somebody needs to blog about that so I can rant again… 🙂
Btw, James, to make your code more understandable, you’d be wise to name your “cases” variable well. I know that your code is a facetious example. I’m just saying.
Also, watch out for context. As you know, it gets lost when you dereference methods. (They’re just function pointers when you dereference them in Javascript.) For instance:
There are many ways to solve this including dojo’s hitch() and prototype’s bind().
so nice, write less do more!!
First of all academically such a thing is considered a trick and inefficient.
If you are looking at it for problems that require not using switch then fine but if you think switch is unnecessary, by the same token you could assume Object Oriented Programing and modern compilers are also unnecessary because, hey there is nothing that can’t be done in assembly language.
In reality when switch is used, compilers create the if/else statements for you. That is machine code level goto statements that don’t require holding a value somewhere in order to figure the post condition and then jumping there. Thus switch is a really nit way of representing large number of pre and post conditions and honestly it’s cleaner syntax than what you propose.
You can bet your bottom dollar that creating objects to represent conditions is not going to help your program run faster.
if you really analyze your code you will realize that the following actually happens:
1. hash table is created for (var focusMethod = {}).
2. hash methods are executed to find the location of your keys
3. values are assigned to the hash entry
4. then hash table is queried with a key
5. if there is a returned value
6. query the hash table one more time with the key
7. grab the value
8. execute the value
Also your code is going to always dump the previous object in focusMethod and create a new one. Imagine running it within a loop that iterates a million times. It’s just not smart. You probably will need to write something like this:
and honestly if you are going through the trouble of writing an if statement around where you create a new object to represent pre and post conditions, and/or that’s how you think about optimizing code then you shouldn’t include your sample code in your resume.
I promise you that rendering routines in Adobe photoshop aren’t programmed this way. Real time airplane safety features aren’t programmed like that and pretty much any thing that is substantial isn’t programmed this way.
@A, thanks for taking the time to write your comment. I understand that my proposal, and generally the idea of lookup tables may not easily compare to the speed of native switch statements but I still think that using objects to store conditions is cleaner and can be the better solution in certain situations.
Plus, web programming cannot really be prepared to any other type of programming (like “Real time airplane safety”). The basic principles may still hold true but there is a much higher demand for code customization on the web. Storing conditions extends this principle; it allows you and other contributors to change/debug conditions without having to go digging through the source looking through line after line of cases.
Speed/performance, especially when operating at such a high abstraction layer, is largely moot. I understand that we still need to take these things into consideration but today, right now, I consider readability and general code maintainability to be a much higher priority. The question of whether the syntax is cleaner is subjective and therefore really isn’t worth mentioning.
@unscriptable, another way:
Multiple return paths may annoy you, but this is even worse IMO:
I know, I know, it’s subjective, but I just really hate this… It looks like the author wanted to follow the “single entry, single exit” rule regardless of what was practical. What’s so bad about multiple return paths anyway? – sure, over-usage is ugly, but if used wisely it’s not that bad IMO.
It’s a good idea to mention that Javascript objects are quite lousy at emulating proper hash tables, due to their prototypical nature and inability to modify their internal prototype chains (non-standard implementations aside).
A popular example is probably “toString”/”valueOf” keys which, when accessed on a plain object, resolve to `Object.prototype.toString/valueOf` respectively. Keys, matching other `Object.prototype.*` properties (either built-in or user-defined) have similar outcome.
Explicitly modifying keys before property access usually solves this “problem” nicely, albeit in expense of additional overhead. Other solutions, such as `hasOwnProperty`, are either not widely supported (e.g. Safari 2 lacks it) or are not reliable (e.g. `hasOwnProperty(‘__proto__’)` is `true` on plain objects in Gecko-based browsers).
I strongly recommend on learning the alternatives using object oriented code… not sure all of them will apply for JavaScript… though they will defently be relevant for PHP, Java & C#. Best, Haim.
Great!
But,how to transfer this to your method?
http://dbj.org/dbj/?p=119
I think you might find this an interesting angle on the same theme …
–DBJ
@Dusan – Very interesting article, thanx for the link! With a quick hack to allow single or array alternatives, the “cond” function that DBJ defines could be made to accomodate Kzz’ example above:
Fallthrough could now be emulated giving an array for some values:
And kzz conditional bit could be done like so:
Finally, James’ original function lookup example (although missing the defined check):
Quite cute, I think! Although, as DBJ writes in his article, the actual value is obviously debatable.
…argh, sorry about the messed-up > and < ! James, help, how do I prevent that?
Yeah! Lets Re-invent the wheel!
The switch is much more elegant than if/else. Also, it haves a default statement, witch provides more security on web apps.
There’s a reason for it to be there.
That’s a nice approach the one you wrote, but its only useful on some very specific situations.
BTW, I think standards are a nice way to share code among other developers and other coders who might have to mess up with your code and will not need to ‘translate’ your logic.
excuse me, but this MacGyver hack’on’crack code isn’t very good…
there is very good reasons when to use switch-case:
– when performance is an issue
– when each token i distinct (or nearly)
– when the context matters
– when other people read your code (as stated by Antonio)
i’ve used switch-case when formulating my code-parser in this way (which is the fastest and best way to do so)
which performs REALLY good, and carries the context throughout the switch selector…
ofcause you could upgrade the lookup to take the context on call:
but wouldn’t perform as good as the switch-case because of the copy of context in each call..
… and because the lookup is used 2 times to find the element in the object.
@kzz : You’ll need to change this code, indeed. It simply doesn’t work, the value between the ‘case’ and the ‘:’ must be a constant value which is then compared (==) with the subject of the switch statement (switch(subject)). You may want to use a “else-if” structure.
I often use this in the same conditions as a switch but when I know that the first conditions are more likely to happen.