This switch statement compiles. Should it be allowed?

I was presented an interesting gotcha with the Go switch statement today.

Consider the following

package main

import "fmt"

func f() bool {
  return false
}

func main() {
  switch f()
  {
  case false:
    fmt.Println(1)
  case f():
    fmt.Println(2)
  case true:
    fmt.Println(3)
  default:
    fmt.Println(4)
  }
}

This prints 3.

The gotcha (which most editors won’t catch) is having the curly brace on the next line after the switch statement. I am wondering why this is allowed at all? And if those case statements are still tied to the switch statement that precede them.

Thanks

I’ve never seen any bug caused by something like this in the real world. And in the real world, tooling will go fmt your code. Try pasting this into the go playground for example and your problem will become apparent as soon as you click “run” (which formats your code as well). From a tour of go:

Go’s switch is like the one in C, C++, Java, JavaScript, and PHP, except that Go only runs the selected case, not all the cases that follow. In effect, the break statement that is needed at the end of each case in those languages is provided automatically in Go. Another important difference is that Go’s switch cases need not be constants, and the values involved need not be integers.

Like I said - I’ve never seen a bug caused by something like what you’ve written above. However, I have seen a LOT of bugs that were prevented in go due to the fact that it implicitly adds break statements. Anyway, if you run your code on the go playground you’ll see what is happening. And in essence your code is the same as switch without a condition:

Switch without a condition is the same as switch true.

See also:

https://gobyexample.com/switch

I am not a “decompile” expert vut i guess than a switch statement
is a just “shorthand” way to write a bunch of nested if…else…if
this code

 switch f(); {
case false:
    fmt.Println(1)
case f():
    fmt.Println(2)
case true:
    fmt.Println(3)
default:
    fmt.Println(4)
}

it is running as :

 f()
if false {
fmt.Println(1)
} else if f() {
fmt.Println(2)
} else if true {
fmt.Println(3)
} else {
fmt.Println(4)
}

Just add an Println to f function to check how many times is executed (2 times)

func f() bool {
 fmt.Println("f() Called")
return false
}

You could investigate further on this site (which shows you generated assembly-code) and report back :wink:
(I edited your example in it already and used an ARM64 Go-compiler…)

Great!!! I just add this tool my tool-set just for curiosity…!!! thanks!!!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.