Why should I use named constants instead of literal values in comparisons?

← Comparison Patterns · Ref: Q638

EK9 detects when both sides of a comparison are literal values and raises E08082. The result is always a compile-time constant, making the comparison pointless.

THE PROBLEM

Comparing two literals like '18 > 10' always produces the same result. This is dead code: the condition is predetermined. It typically indicates that the developer meant to compare a variable against a constant but accidentally used two constants.

CORRECT PATTERN

Use a named constant on one side and a variable on the other:

  if age >= MINIMUM_AGE
  if temperature > BOILING_POINT
  if count == EXPECTED_COUNT

NAMED CONSTANTS

Declare constants in a defines constant block:

  defines constant
    MINIMUM_AGE <- 18
    MAXIMUM_SPEED <- 120

This gives the literal a meaningful name and avoids magic numbers throughout the code.

WHY NAMED CONSTANTS MATTER

Self-documenting: 'MINIMUM_AGE' explains the intent. Single source of truth: change the value in one place. Avoids E08082: variable vs constant is a genuine comparison. Avoids E11065: magic literals in comparisons.

See Q637 for self-comparison detection. See Q558 for tautological conditions. See Q639 for Boolean comparison patterns.

Example

defines module qa.comparison.namedconstants

  defines constant

    MINIMUM_AGE <- 18

    MAXIMUM_AGE <- 120

    PASSING_SCORE <- 60

    SPEED_LIMIT <- 65

    BOILING_POINT <- 100.0

    FREEZING_POINT <- 0.0

  defines function

    <?-
      Correct: compares a variable against a named constant.
      Replacing the variable with a literal would trigger E08082.
    -?>
    isAdult() as pure
      -> age as Integer
      <- adult as Boolean: age >= MINIMUM_AGE

    <?-
      Correct: variable compared against named constant.
    -?>
    isPassing() as pure
      -> score as Integer
      <- passing as Boolean: score >= PASSING_SCORE

    <?-
      Correct: variable compared against named constants for range check.
    -?>
    isValidAge() as pure
      -> age as Integer
      <- valid as Boolean: age >= MINIMUM_AGE

      if age > MAXIMUM_AGE
        valid: false

    <?-
      Correct: Float variable compared against named constant.
    -?>
    isBoiling() as pure
      -> temperature as Float
      <- boiling as Boolean: temperature >= BOILING_POINT

    <?-
      Correct: uses named constants for range classification.
    -?>
    classifyTemperature() as pure
      -> temperature as Float
      <- classification as String: "normal"

      if temperature >= BOILING_POINT
        classification: "boiling"
      else if temperature <= FREEZING_POINT
        classification: "freezing"

  defines program

    NamedConstantsDemo()
      stdout <- Stdout()

      stdout.println(`Is 21 adult? ${isAdult(21)}`)
      stdout.println(`Is 15 adult? ${isAdult(15)}`)

      stdout.println(`Score 75 passing? ${isPassing(75)}`)
      stdout.println(`Score 40 passing? ${isPassing(40)}`)

      stdout.println(`Age 25 valid? ${isValidAge(25)}`)
      stdout.println(`Age 150 valid? ${isValidAge(150)}`)

      stdout.println(`100C boiling? ${isBoiling(100.0)}`)
      stdout.println(`50C boiling? ${isBoiling(50.0)}`)

      cls <- classifyTemperature(105.0)
      stdout.println(`105C: ${cls}`)

Common mistakes

E08082 — Comparing two literal values produces a compile-time constant, making the comparison dead code. Compare a variable against a named constant instead. See ek9 -h E08082 for details.

Incorrect:

adult as Boolean: 18 >= 18

Correct:

adult as Boolean: age >= MINIMUM_AGE

E11064 — Using a raw literal 120 in a comparison is a magic literal. Use the named constant MAXIMUM_AGE instead. See ek9 -h E11064 for details.

Incorrect:

if age > 120

Correct:

if age > MAXIMUM_AGE
Other ways to ask this
  • Why does EK9 reject literal-vs-literal comparisons?
  • Why does EK9 reject comparing two literal values?
  • How do I fix a magic number comparison error?

Coming from another language?

Java: no compile-time constant comparison detection. SonarQube flags magic numbers as code smell (optional). Rust: clippy has absurd_extreme_comparisons lint. Go: no magic number detection. Python: pylint magic-value-comparison. C++: -Wtautological-compare for some literal comparisons. EK9: E08082 mandatory error for literal-vs-literal comparison, E11065 for magic literals.

Keywords: migrate, E11065, number, value, comparison, named, E08082, magic, dead, pattern, literal, constant