ID:133372
 
From the reference (under switch): The "break" instruction may be used to exit from the switch statement.

This is not true.
I'm not sure if it SHOULD, or SHOULDN'T, but it doesn't, so...

I've been aware of it for some time, but I've never gotten around to reporting it.
It's not exactly a bug, so I'll just stick it in here.
Keeth wrote:
From the reference (under switch): The "break" instruction may be used to exit from the switch statement.

This is not true.
I'm not sure if it SHOULD, or SHOULDN'T, but it doesn't, so...

I've been aware of it for some time, but I've never gotten around to reporting it.
It's not exactly a bug, so I'll just stick it in here.

Since I know from personal experience that this is not the case, I submit that your code is using break incorrectly. If you have a loop or another switch() inside one of the blocks of your switch(), then you're only breaking from the inner one and not the outer.

Lummox JR
In response to Lummox JR
switch(1)
if (1) break


This produces an error: error:break :not in a loop
In response to Keeth
switch("cake")
if ("cake") break


I get the same exact error, error:break :not in a loop.
In response to Keeth
Don't quote me on this, but I bet the compiler is smart enough to determine that constants will never evaluate as anything different, so {switch(1) if(1) break} probably evaluates as {if(1) break}.

Also, I don't believe switch() statements require breaks, I think they break when a condition is met automatically.
In response to CaptFalcon33035
In languages such as C, C++, and Java, break is used to separate each check for a constant value.

@CaptFalcon33035: What you said is true. If a condition is met, rest of the switch block is skipped. But I do not understand what you meant about the compiler being smart enough.
In response to Kakashi24142
But I do not understand what you meant about the compiler being smart enough.

He means that the expression being evaluated in the if() is definitely going to be equivalent to the expression in the switch statement, and the compiler understands this. But for one, the expression in the switch() statement can be indefinite, and two, the error has nothing to do with it being too smart. It is saying it's not being used in a loop. (besides, that wouldn't be a very smart reaction, I'd think)

What you said is true. If a condition is met, rest of the switch block is skipped.

I understand this.
But there are also situations where you may still want to use break anyway.

switch(rand(0,2))
if (0) // whatever
if (1) break
else // whatever

// it should only do something when 0 or 2 is provided
// this way the else doesn't process if it is 1
// technically you can just leave the "if (1)" statement empty, but that's kind of ugly.


Of course there may not be MANY situations, but there are probably one or two.
I know I've been in a situation like that in the past.

Anyway, this was just to report that the reference was not accurate in saying that break breaks out of switch statements.
I'm not questioning its usage.
In response to Keeth
Well, for a temporary workaround--

It seems dumb to enter a loop that you can skip beforehand. For me, I only use switch() when the value being checked against is predictable--something I can be certain of.

var/random = rand(0,2)
if(random != 1)
switch(random)
if(0)
else
In response to CaptFalcon33035
You're using if() on the same expression in your "workaround", so it partly beats the purpose of using switch(). =P All you'd need to do for that situation was place if(1) directly under the switch() and do nothing in that case, like Keeth mentioned - but you seem to be talking as if the example by Keeth would be the only possible usage. =P It could always be potentially useful as a convenient bail-out of the code block, like you bail out with return, but only outside the statement of course.
switch(something)
if(value)
do_stuff
if(!(necessary_condition)) //if something is 'wrong'
break //bail out
do_some_more_stuff
if(value2)
//...


This might be broken (pun intended), since the DM Reference says it should work, though not necessarily. It may have never worked, but been planned or something at the time the old Reference entry was written.
Well, for the time being you still have goto in case you need this feature.
Is there a legitimate case where you would ever need to break from a switch() anyways?. It's not like switch() cases fall through, like in other languages.
In response to Kuraudo
Well, I never considered any legitimate cases, but I knew it said it should work and it doesn't so I figured I'd report it.

There probably aren't, or at least any that can't be avoided.

But I mean, Lummox even said it SHOULD work, so...

Anyway, just reporting it.
In response to Keeth
Oh, but it can <.<

If the switch() itself is in a loop.

mob/var/L

mob/proc/CheckL()
for(var/client/C)
switch(C.mob.L)
if(1) break
if(2)
Given that BYOND doesn't fall through in switch() statements, I'm not sure that reference is even necessary.

In C++, for instance:
switch(value) {
case 1:
cout << "One!" << endl;
case 2:
cout << "Two!" << endl;
}


prints (when value is equal to 1):
One!
Two!

In DM:
switch(value)
if(1)
usr << "One!"
if(2)
usr << "Two!"


prints (when value is equal to 1):
One!

If you want to exit a switch() based on a certain value (i.e., have a default condition that does nothing), I just use if(1); (note the semicolon) which is a do-nothing statement.
In response to Andre-g1
I'd assume that's breaking the for loop, not the switch...
In response to Kaioken
I hate to resurrect such an old post, but I personally am having a problem related to this, so...

Basically it's just like what Kaioken has there. Something can be "wrong" and I need to "exit" the switch statement, but that's impossible at the moment.

My only options are to maybe make a separate function that can simply escape from when I hit an error like this (which means an entirely new function and I have to change the way I handle this particular process), or I can do something very ugly like:

if problem
tell them it's bad
else
if another problem
tell them it's bad
else
if another problem
tell them it's bad
else
do the thing we wanted

// or
if problem
tell them it's bad
error = true

if problem
tell them its bad
error = true

if error != true
do the thing we wanted


It's not absolutely necessary... it'd just be really nice to have.
In response to Keeth
This is probably one of those rare instances when 'goto' might be acceptable. Just put a label at the end of the switch() and goto that label if you need to. That's how we did it in 'old school' languages =P.
In response to Keeth
Usually logic that complex is best handled in one of two ways: Use goto, or farm it out to another proc. Essentially the logic there boils down to a need to get a yes/no decision. In a separate proc, you can use separate return points to preserve a good flow of logic. I would tend to prefer putting this into a proc for that reason.

if(problem1) return 0
if(problem2) return 0
if(problem3) return 0
return 1


If an error message is required, then you can use the absence of an error to signal readiness to proceed.

if(problem1) return "It's bad because of problem 1."
if(problem2) return "It's bad because of problem 2."
if(problem3) return "It's bad because of problem 3."
return null // all clear


Lummox JR