How does EK9 enforce complexity limits and what triggers E11010?

← Code Quality · Ref: Q696

EK9 measures cyclomatic complexity per function and method. Exceeding the threshold triggers a compile error, forcing decomposition into smaller units.

CYCLOMATIC COMPLEXITY (E11010)

Each branch point (if, else, switch case, for, while, guard) adds one to complexity. The compiler sets a threshold and rejects functions that exceed it.

METHOD COMPLEXITY (E11012)

Methods within classes are checked individually. A method with too many branch points triggers E11012.

STAYING WITHIN LIMITS

1. Decompose into smaller pure functions
2. Use guard expressions to flatten nesting
3. Use switch instead of chained if/else
4. Extract complex conditions into named Boolean variables

FUNCTIONAL DECOMPOSITION

EK9 encourages extracting logic into small, focused pure functions:

  // Instead of one complex function:
  //   processOrder() with 20 branches
  // Use:
  //   validateOrder() + calculateTotal() + applyDiscount()

See Q316 for complexity metrics. See Q322 for quality enforcement. See Q310 for code quality overview.
See Q728 for nesting depth boundary. See Q733 for combined complexity boundary.

Example

defines module qa.codequality.complexitylimits

  defines constant

    LOW_THRESHOLD <- 10
    MEDIUM_THRESHOLD <- 50
    HIGH_THRESHOLD <- 90
    PASSING_SCORE <- 60

  defines function

    <?-
      Small focused function: low complexity.
      Single responsibility, easy to test.
    -?>
    classifyScore() as pure
      -> scoreValue as Integer
      <- classification as String: "average"

      if scoreValue < LOW_THRESHOLD
        classification: "very low"
      else if scoreValue < MEDIUM_THRESHOLD
        classification: "low"
      else if scoreValue < HIGH_THRESHOLD
        classification: "high"
      else
        classification: "very high"

    <?-
      Another small function: validates a single aspect.
    -?>
    isPassing() as pure
      -> scoreValue as Integer
      <- passing as Boolean: scoreValue >= PASSING_SCORE

    <?-
      Composing small functions keeps complexity low.
      Each function does one thing, combining them is straightforward.
    -?>
    generateReport() as pure
      -> scoreValue as Integer
      <- report as String: ""

      classification <- classifyScore(scoreValue)
      passed <- isPassing(scoreValue)

      if passed
        report: `${classification} (PASS)`
      else
        report: `${classification} (FAIL)`

  defines program

    ComplexityWithinLimitsDemo()
      stdout <- Stdout()

      scores <- [85, 42, 95, 15, 60]
      for scoreValue in scores
        stdout.println(generateReport(scoreValue))

Common mistakes

E50060 — String has no toUpperCase() method in EK9. Use upperCase() instead. See ek9 -h E50060 for details.

Incorrect:

stdout.println(generateReport(scoreValue).toUpperCase())

Correct:

stdout.println(generateReport(scoreValue))

E50060 — String has no toUpperCase() method in EK9. Use upperCase() instead. See ek9 -h E50060 for details.

Incorrect:

classification <- classifyScore(scoreValue).toUpperCase()

Correct:

classification <- classifyScore(scoreValue)
Other ways to ask this
  • What is E11010 cyclomatic complexity exceeded?
  • What is E11012 method too complex?
  • How do I keep functions within complexity limits?
  • What are the complexity thresholds in EK9?

Coming from another language?

Java: complexity checked by static analysis tools (optional). Python: no built-in check. C++: no built-in check. Rust: Clippy complexity warning (optional). Go: no built-in check. EK9: complexity is a compile error, not a warning.

Keywords: metric, threshold, quality, E11012, limit, E11010, decomposition, complexity, clean-code, cyclomatic