Implicit blocks

June 14, 2023

On Monday we saw how to create explicit code blocks in Go. Now we’ll breeze through the list of implicit code blocks that exist.

Blocks

In addition to explicit blocks in the source code, there are implicit blocks:

  1. The universe block encompasses all Go source text.
  2. Each package has a package block containing all Go source text for that package.
  3. Each file has a file block containing all Go source text in that file.
  4. Each “if”, “for”, and “switch” statement is considered to be in its own implicit block.
  5. Each clause in a “switch” or “select” statement acts as an implicit block.

Blocks nest and influence scoping.

Starting tomorrow, we’ll talk about scoping, where most of this starts to make more sense. But for today I want to call out one of these implicit scoping rules that’s a bit suprising to some.

Number 4 says that “Each ‘if’ … is considered to be its own implicit block.”

This seems intuitive enough at first…

if x := foo(); x > 3 {
	fmt.Printf("x = %v\n", x)
}

The variable x is accessible within the body of the if statement, because its declaration happens with the simple statement (a concept we’ll get to) in the if statement.

What’s not as obvious is that this implicit scope actually extends to any else or else if clauses of the same if statement:

if x := foo(); x > 3 {
	fmt.Printf("x = %v\n", x)
	return
} else if x < 0 {
	fmt.Println("x is too small", x)
	return
} else {
	fmt.Println("x is just right", x)
	return
}

Notice that the x variable is accessible within the else if and else blocks as well. But if we rewrite this code, as below, we lose that scoping, and x is undefined:

if x := foo(); x > 3 {
	fmt.Printf("x = %v\n", x)
	return
}
if x < 0 {  // x is not defined
	fmt.Println("x is too small", x)
	return
}
fmt.Println("x is just right", x) // x is not defined
return

To make this code work without the elses, we have to pull x’s assignment out of the implicit if block:

x := foo() // x is defined outside of the implicit if block
if x > 3 {
	fmt.Printf("x = %v\n", x)
	return
}
if x < 0 {
	fmt.Println("x is too small", x)
	return
}
fmt.Println("x is just right", x)
return

Quotes from The Go Programming Language Specification Version of December 15, 2022


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Get daily content like this in your inbox!

Subscribe