Concepts / Compile-time Error Checking

Compile-time Error Checking

Static assertions perform simple checks on properties known at compile time and report failures as compiler error messages.

  • Programming

A Wrong Assumption and Two Discovery Points

Suppose you write a program and one of its assumptions is wrong. Perhaps you assumed something about a type that you use in the code, and that assumption does not hold. The mistake will eventually be noticed, but the moment it is noticed can differ a great deal. It might be noticed while the program is being compiled, or it might be noticed later, while the program is actually running.

The source material treats these two moments as very different. A mistake caught while the program is compiled is reported before the program ever executes. A mistake caught while the program runs may only appear when the program reaches the place where the problem occurs. This article focuses on the first kind of detection, which is called compile-time error checking, and on the mechanism that supports it, the static assertion.

Following One Failing Check

Before looking at definitions, follow one failing check through its steps. The focus here is only on the order of events. A static assertion is a simple check on a property that is known at compile time. When the compiler reaches the check, it evaluates the condition. If the condition is true, nothing goes wrong and the compilation continues. If the condition is false, the failure is reported as a compiler error message.

Notice what this sequence does not require. It does not require the program to be running, and it does not require any user input. The compiler only needs the property it is inspecting, and that property is already fixed at this stage. This is the reason the failure can be reported early.

Compile Time Versus Run Time

Exceptions are the mechanism that reports errors found at run time. Static assertions report errors found at compile time. Both mechanisms answer the same underlying question, which is whether something is wrong, but they answer it at different points in a program's life. An exception needs the program to be running and to reach the point where the problem occurs. A static assertion needs only the compiler, because the property it inspects is already known at that stage.

The timeline shows the practical difference. A compile-time error is found during the build, before the program executes at all. A run-time error can only be found after the program has started and reached the relevant code. For a broken assumption about a fixed property of a type, the compile-time route catches the problem earlier in the life of the program.

Which Properties Qualify for a Check

The defining requirement for a static assertion is that the property must be known at compile time. A value that depends on input the user types while the program runs cannot be checked this way, because the compiler does not have that value yet. A property that is fixed by the code and its types is a candidate for a static assertion.

The two columns separate the candidates from the non-candidates. The left column contains facts about the program that exist before it runs. The right column contains values that only exist once the program is executing, so a static assertion cannot inspect them.

Why Earlier Detection Is Preferred

The source states plainly that when an error can be found at compile time, it is usually preferable to find it there. The type system and the facilities for specifying the interfaces of user-defined types exist largely to make this possible. They let the compiler reject many misuses before a program is ever run. Static assertions extend the same idea to other properties that are known at compile time but are not captured by the type system or an interface declaration.

Worked example

A broken assumption about a fixed property

A program assumes that a particular type is at least a certain size. Suppose the assumption is wrong for the environment where the code is built. Trace where the mistake can be reported.

  1. 1
    Identify the property

    The size of a type is fixed by the time the code is built, so it is a property known at compile time and a candidate for a static assertion.

  2. 2
    Place the check

    A static assertion is written to test the assumption. Its condition compares the fixed property against the required size.

  3. 3
    Compile the program

    The compiler evaluates the condition. Because the assumption is false, the failure is reported as a compiler error message.

  4. 4
    Compare with the run-time alternative

    Without the static assertion, the same wrong assumption might only surface later, when the program runs and reaches the code that depends on it.

Result

The broken assumption is reported before the program executes, rather than after it has been deployed and run.

Mistakes Learners Make with Compile-time Checks

  • Common mistake

    Assuming a static assertion can check a value the user types in

    What it looks like

    Trying to assert that a number read from the keyboard is positive.

    Why it fails

    The compiler does not have that value yet, because it only exists while the program runs.

    Do this instead

    Use a run-time check for values that depend on input, and reserve static assertions for properties known at compile time.

  • Common mistake

    Treating a compile-time failure and a run-time exception as the same thing

    Why it fails

    They report errors at different points in the program's life. An exception needs the program to run and reach the problem, while a static assertion needs only the compiler.

  • Common mistake

    Assuming an early failure means the problem is less serious

    Why it fails

    Finding a problem early does not reduce its importance. It only means the problem is reported before the program executes, which is the reason the source prefers this route when it is available.

Predicting When a Failure Appears

What do you think happens?

A check depends on a number that a user types while the program is running. Can this be verified with a static assertion?

  • Yes, because the compiler can read the number ahead of time

  • No, because the property is not known until the program runs

Reveal answer
Answer:

No, because the property is not known until the program runs

A static assertion checks properties known at compile time. A value that depends on user input does not exist yet when the compiler runs, so the check must be made at run time.

EASY

For each property below, decide whether it is a suitable target for a static assertion or whether it must be checked at run time: the size of a fixed type, a constant defined in the code, and the contents of a file the user selects after the program starts. Explain your reasoning in terms of when each value becomes known.

Hints
  • Ask whether the value exists before the program is run.
  • Values fixed by the code and its types are known at compile time.

Summary of Compile-time Checking

  1. 1
    Exceptions report errors found at run time, while static assertions report errors found at compile time.
  2. 2
    A static assertion evaluates a simple condition on a property known at compile time, and a failed check is reported as a compiler error message.
  3. 3
    A property is a suitable target only when it is known before the program runs, so values that depend on runtime input cannot be checked this way.
  4. 4
    When an error can be found at compile time, detecting it there is usually preferable, which is the purpose of the type system and interface facilities for user-defined types.

At a glance

  • Exceptions report errors found at run time, while static assertions report errors found at compile time.
  • A static assertion checks a property known at compile time, and a failed check is reported as a compiler error message.
  • Only properties known before the program runs are suitable targets, so runtime input cannot be checked this way.
  • Detecting an error at compile time is generally preferred, because the problem is reported before the program executes.

More concepts starting with C