120

I saw a few answers to this issue, and I get it — you can't declare and assign variables inside a switch. But I'm wondering if the following is correct at throwing an error saying

error: expected expression before 'int'

Code:

switch (i) {
    case 0:
        int j = 1;
        break;
}

Why would putting a call to NSLog() before it result in no errors?

switch (i) {
    case 0:
        NSLog(@"wtf");
        int j = 1;
        break;
}
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
dizy
  • 7,951
  • 10
  • 53
  • 54
  • 1
    This has been asked (at least) twice before: http://stackoverflow.com/questions/92396/why-cant-variables-be-declared-in-a-switch-statement http://stackoverflow.com/questions/1115304/can-i-declare-variables-inside-an-objective-c-switch-statement – Adam Rosenfield Aug 05 '09 at 15:42
  • 2
    True, but both of those questions are still open. I don't see a problem with letting this one alone — no need to vote to close it... – Quinn Taylor Aug 05 '09 at 16:25
  • 1
    Adam, while the other post answers the error, it didn't address the fact that putting an expression as the first call would actually avoid the error. Something Quinn has answered here. – dizy Aug 05 '09 at 22:20

3 Answers3

148

You actually can declare variables within a switch if you do it according to the syntax of the language. You're getting an error because "case 0:" is a label, and in C it's illegal to have a declaration as the first statement after a label — note that the compiler expects an expression, such as a method call, normal assignment, etc. (Bizarre though it may be, that's the rule.)

When you put the NSLog() first, you avoided this limitation. You can enclose the contents of a case in { } braces to introduce a scoping block, or you can move the variable declaration outside the switch. Which you choose is a matter of personal preference. Just be aware that a variable declared in { } braces is only valid within that scope, so any other code that uses it must also appear within those braces.


Edit:

By the way, this quirk isn't as uncommon as you might think. In C and Java, it's also illegal to use a local variable declaration as the lone statement (meaning "not surrounded by braces) in a for, while, or do loop, or even in if and else clauses. (In fact, this is covered in puzzler #55 of "Java Puzzlers", which I highly recommend.) I think we generally don't write such errors to begin with because it makes little sense to declare a variable as the only statement in such contexts. With switch / case constructs, though, some people omit the braces since the break statement is the critical statement for control flow.

To see the compiler throw fits, copy this horrific, pointless snippet into your (Objective-)C code:

if (1)
    int i;
else
    int i;
for (int answer = 1; answer <= 42; answer ++)
    int i;
while (1)
    int i;
do
    int i;
while (1);

Yet another reason to always use { } braces to delimit the body of such constructs. :-)

Quinn Taylor
  • 44,553
  • 16
  • 113
  • 131
  • wow, thats weird... but thanks! – dizy Aug 05 '09 at 05:11
  • 9
    Generally, if the variable is used only within the single case, then enclosing the case section in { } will be better form (it avoids it being accidently reused later). If the variable is used againlater, then it really makes more sense to declare it before the start of the switch statement, since its very obtuse otherwise. – Peter N Lewis Aug 05 '09 at 05:28
  • I totally agree, using a nested scope with braces does make the intent crystal clear and can prevent incidental bugs. Thanks for clarifying! – Quinn Taylor Aug 05 '09 at 05:40
  • 1
    Wow, even C# has the problem. For the simple code `if (true) int i = 0;` I get the following error message in Visual Studio before I even compile: `Embedded statement cannot be a declaration or labeled statement` Amazing. – mkmurray Aug 05 '09 at 15:47
  • 3
    Not surprising. It's nice that the error from C# is actually a bit more clear than the gcc error. And actually, I'm not sure I'd classify it as a "problem"... more of an intentionally prohibited syntax. I would guess that most C-based languages act similarly. – Quinn Taylor Aug 05 '09 at 16:15
  • 1
    Yes, I apologize. I understand why the syntax is prohibited as it is pointless to declare a variable that will immediately lose scope. I will say one thing more, however, that C# allows this switch syntax prohibited here in Objective-C. It's the other statements (if, else, for, while, and do) that get this error message. – mkmurray Aug 05 '09 at 16:21
  • 1
    I actually decided to blog about it and even investigated into the C# Language Spec grammar: http://murrayon.net/2009/09/variable-declaration-restrictions.html – mkmurray Sep 24 '09 at 14:56
  • "note that the compiler expects an expression, such as a method call, normal assignment, etc. (Bizarre though it may be, that's the rule.)" -> I would ask "Why" is that rule imposed !? – Paweł Brewczynski Jan 06 '15 at 22:04
50

I've run into this issue before, and the conclusion was that you just put the code inside a block.

switch (i) {
case 0:
    {
        int j = 1;
        break;
    }
}
newacct
  • 119,665
  • 29
  • 163
  • 224
4

Another simple workaround I use is to add an empty expression (semicolon) before the declaration. This avoids limiting the variable scope to a code block (or having some case statements with code blocks and some without).

switch (i) {
    case 0:;
        int j = 1;
        break;
}
Joel
  • 15,654
  • 5
  • 37
  • 60