29

I have recently learned that you can use a neat switch statement with fallthrough to set default argument values in Javascript:

function myFunc(arg1, arg2, arg3) {
    //replace unpassed arguments with their defaults:
    switch (arguments.length) {
        case 0 : arg1 = "default1";
        case 1 : arg2 = "default2";
        case 2 : arg3 = "default3";
    }
}

I have grown to like it a lot, since not only is it very short but it also works based on parameters actually passed, without relying on having a special class of values (null, falsy, etc) serve as placeholders as in the more traditional versions:

function myFunc(arg1, arg2, arg3){
    //replace falsy arguments with their defaults:
    arg1 = arg1 || "default1";
    arg2 = arg2 || "default2";
    arg3 = arg3 || "default3";
}

My inital though after seeing the version using the switch was that I should consider using it "by default" over the || version.

The switch fallthough makes it not much longer and it has the advantage that it is much more "robust" in that it does not care about the types of the parameters. In the general case, it sounds like a good idea to not have to worry about what would happen with all the falsy values ('', 0, null, false ...) whenever I have to make a function with default parameters.

I would then reserve the arg = arg || x for the actual cases where I want to check for truthyness instead of repurposing it as the general rule for parameter defaulting.

However, I found very few examples of this pattern when I did a code search for it so I had to put on my skeptic hat. Why didn't I find more examples of this idiom?

  • Is it just now very well known?
  • Did I not search well enough? Did I get confused by the large number of false positives?
  • Is there something that makes it inferior to the alternatives?

Some reasons that I (and some of the comments) could think of for avoiding switch(arguments.length):

  • Using named parameters passed via an object literal is very flexible and extensible. Perhaps places where more arguments can be optional are using this instead?

  • Perhaps most of the time we do want to check for truthyness? Using a category of values as palceholders also allows default parameters to appear in the middle instead of only at the end : myFunc('arg1', null, 'arg3')

  • Perhaps most people just prefer the very short arg = arg || "default" and most of the time we just don't care about falsy values?

  • Perhaps accessing arguements is evil/unperformant?

  • Perhaps this kind of switch case fallthrough has a bad part I didn't think about?

Are these cons enough to avoid using switch(arguments.length) as a staple default argument pattern or is it a neat trick I should keep and use in my code?

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • 7
    I never knew of this idiom, but looking at it there is at least one caveat I can see - passing `undefined` makes `arguments.length === 2`, while you probably want to replace a passed `undefined` with the default value as well (like `||` does). – pimvdb Jan 05 '12 at 14:29
  • 2
    Interesting approach. Though it would only work if one always provides all the preceding parameters. For example, jQuery allows you to omit parameters in the middle, such as `$.get(url, callback)` instead of `$.get(url, data, callbacl)`. `switch` could not make the distinction between different parameter types. It would also fail if "fill parameters" are passed, such as `foo(1, null, 3)` because one wants to set the third parameter but not the second one (*edit* what pimvdb said). So maybe these are the reasons why it is not that popular; it's not flexible enough. – Felix Kling Jan 05 '12 at 14:29
  • 2
    I would think another reason this isn't used, is because it requires additional work if you refactor the method to have a different signature whereas the typical method would still work fine. – Justin Breitfeller Jan 05 '12 at 14:35
  • Re first comment, at least in Chrome, parameters passed as undefined are counted in arguments.length – HBP Jan 05 '12 at 15:30
  • @Hans B PUFAL: It looks like we're on the same page. `myFunc(undefined, undefined)` will not alter the first two `undefined`s, but will alter the third `undefined`. – pimvdb Jan 05 '12 at 15:46
  • This isn't a constructive question. – Daniel A. White Jan 05 '12 at 17:42
  • This question should be _closed_. – Daniel A. White Jan 05 '12 at 17:48
  • @DanielA.White: Well, the phrasing might not have been the best but I still think it makes sense to compare this idiom with the other ones in order to be able to make an informed choice when writing my code. – hugomg Jan 05 '12 at 17:53
  • 1
    please edit your question and clarify that. – Daniel A. White Jan 05 '12 at 17:54
  • I think it's constructive enough. – Lightness Races in Orbit Jan 05 '12 at 18:40
  • 3
    Yeah, I don't see a great reason to close it, and even less to warrant two comments five minutes apart regarding how bad of a question it is. – Dave Newton Jan 05 '12 at 18:44

2 Answers2

7

Since the question has been updated, it's really a matter of opinion. There are a number of javascript features that many people suggest avoiding, such as switch and ternary. This is why there is not a lot of information on some of those features.

The reason that suggestion is made is because many people miss-use those features and create problems in their code. The bugs are sometimes difficult to detect and it can be difficult for others to understand what your code is doing (particularly those unfamiliar with javascript or new programmers).

So if you like to do it that way, and you're not worried about the opinions (or skill level) of anyone working on your code. By all means, your approach will work. I have used the switch statement myself on occasion, and while I don't think it's really "good" or "bad", it's hard to find a situation that requires it.

You asked how I might go about this without an if-else chain:

function myFunc(args) {
    var allArgs = {
        arg1:"default1",
        arg2:"default2",
        arg3:"default3"
    };
    for (var key in args) {
        allArgs[key] = args[key];        
    }
}
myFunc({arg1:null, arg3:'test'})
katspaugh
  • 17,449
  • 11
  • 66
  • 103
Nick Hagianis
  • 1,438
  • 14
  • 20
  • I think the switch pattern was more geared for when the function receives arguments from a list as in `f(arg1, arg2)`. But you have a point in saying the whole discussion is irrelevant since named parameters are usually just better. – hugomg Jan 05 '12 at 21:33
6

Just a guess, but Doug Crockford discourages the use of switch statements in 'JavaScript: the Good Parts.' His logic is that switch statements are a common source of bugs because it's difficult to locate them when using 'fall through' logic. It's easy to see when a case is triggered, but it's often difficult to determine if every case in a result set has been covered, especially if it's not your code.

Ted
  • 1,641
  • 7
  • 30
  • 52
  • +1 There's probably a better way to accomplish what you're trying to do without using a switch statement. some info on good vs bad parts of javascript: http://www.youtube.com/watch?v=RO1Wnu-xKoY – Nick Hagianis Jan 05 '12 at 18:41
  • @NickHagianis: What would be the alternative here though? The usual `||` style has different semantics (as discussed in the question) and using an `if-else` chain is *much* more verbose. – hugomg Jan 05 '12 at 18:47
  • This is a good answer to the question: "Why didn't I find more examples of this idiom?" But I'm not sure that the logic holds up. A lot of JavaScript programmers seem to think that Crockford's opinions on what parts of JavaScript are "good" and "bad" are universally true. Personally, I disagree with Crockford here: switch statements may be quirky, but I've never found them to be a significant source of bugs in any code that uses them. – Daniel Pryden Jan 06 '12 at 03:30