7 Collaborate with the compiler

 

This chapter covers

  • Understanding the strengths and weaknesses of compilers
  • Using compiler strengths to eliminate invariants
  • Sharing responsibility with the compiler

When we are just learning to program, the compiler can feel like an endless source of nagging and nitpicking. It takes things too literally, it gives no leeway, and it freaks out over even the tiniest slip-ups. But used correctly, the compiler is one of the most important elements of our daily work. Not only does it transform our code from a high-level language to a lower-level one, but it also validates several properties and guarantees that certain errors will not occur when we run our program.

In this chapter, we start getting to know our compiler so we can actively use it and build on its strengths. Similarly, we will learn what it cannot do so we do not build on a weak foundation.

When we are intimately familiar with the compiler, we should make it part of our team by sharing the responsibility for correctness with it, letting it help build the software right. If we fight the compiler or trip it up, we are accepting a higher risk of bugs in the future, usually with minimal benefit.

Once we have accepted sharing the responsibility, we must trust the compiler. We need to make an effort to keep dangerous invariants to a minimum, and we need to listen to the compiler’s output—including its warnings.

7.1 Getting to know the compiler

7.1.1 Weakness: The halting problem limits compile-time knowledge

7.1.2 Strength: Reachability ensures that methods return

7.1.3 Strength: Definite assignment prevents accessing uninitialized variables

7.1.4 Strength: Access control helps encapsulate data

7.1.5 Strength: Type checking proves properties

7.1.6 Weakness: Dereferencing null crashes our application

7.1.7 Weakness: Arithmetic errors cause overflows or crashes

7.1.8 Weakness: Out-of-bounds errors crash our application

7.1.9 Weakness: Infinite loops stall our application

7.1.10 Weakness: Deadlocks and race conditions cause unintended behavior

7.2 Using the compiler

7.2.1 Making the compiler work

7.2.2 Don’t fight the compiler

7.3 Trusting the compiler

7.3.1 Teach the compiler invariants

7.3.2 Pay attention to warnings

7.4 Trusting the compiler exclusively