Compile-Time Code Quality Enforcement

Either Good Code or Errors, Never Warnings

EK9 is the first and only mainstream programming language to enforce comprehensive code quality metrics at compile-time. While other languages rely on optional external tools (linters, static analyzers, code quality platforms), EK9 integrates quality enforcement directly into the compiler, making it impossible to compile poor-quality code.

The EK9 Philosophy: If your code compiles, it has passed all quality checks. There are no warnings to ignore, no thresholds to configure, and no external tools to integrate. Quality is enforced by the compiler itself.

This revolutionary approach eliminates technical debt at its source. You cannot accumulate warnings that "will be fixed later" because there are no warnings — only errors that prevent compilation until the code meets quality standards.

Use the -ve (verbose errors) flag to get detailed explanations of any quality violations. See Command Line for more options.


The Quality Pyramid

EK9 enforces quality at five distinct levels, forming a comprehensive quality pyramid. All five layers must pass for code to compile successfully.

                    +-----------------------+
                    |   Duplicate Code      | <- Codebase-level
                    |   Detection (FUTURE)  |    (DRY principle)
                    +-----------------------+
                             ^
                             |
                    +-----------------------+
                    |   Inheritance Depth   | <- Hierarchy-level
                    |   Limits (E11019)     |    (composition > inheritance)
                    +-----------------------+
                             ^
                             |
                    +-----------------------+
                    |   Cohesion/Coupling   | <- Architecture-level
                    |   (E11014, E11015)    |    (SOLID principles)
                    +-----------------------+
                             ^
                             |
                    +-----------------------+
                    |   Complexity Limits   | <- Function-level
                    |   (E11010-E11013)     |    (cognitive load)
                    +-----------------------+
                             ^
                             |
                    +-----------------------+
                    |   Purity and Safety   | <- Expression-level
                    |   (pure keyword)      |    (correctness)
                    +-----------------------+
    

Layer 1: Purity and Safety (Expression-Level)

The foundation of EK9's quality model. Pure functions have no side effects, making code predictable and testable. The pure keyword enforces this at the expression level. Combined with EK9's tri-state semantics and guard expressions, this eliminates entire categories of bugs.

Layer 2: Complexity Limits (Function-Level)

Functions and methods have complexity limits based on cyclomatic complexity. This keeps cognitive load manageable and encourages decomposition into smaller, focused units. See E11010, E11011, and E11013.

Layer 3: Cohesion and Coupling (Architecture-Level)

Classes must maintain high cohesion (methods work together on related data) and low coupling (limited dependencies on external types). This enforces SOLID principles at the architecture level. See E11014 and E11015.

Layer 4: Inheritance Depth (Hierarchy-Level)

Deep inheritance hierarchies make code hard to understand and maintain. EK9 limits inheritance depth and encourages composition via delegation using the by keyword. See E11019.

Layer 5: Duplicate Code Detection (Codebase-Level)

Coming in 2026: IR-based similarity detection will identify duplicated code blocks across your codebase, enforcing the DRY (Don't Repeat Yourself) principle at compile-time.


Why Compile-Time Enforcement?

The Industry Standard Problem

Traditional languages rely on a fragmented ecosystem of optional external tools:

This results in fragmented, optional, bypassable quality enforcement. Warnings accumulate, tools are misconfigured, and technical debt compounds over time.

The EK9 Solution

EK9 replaces this entire fragmented ecosystem with one tool: the compiler.

The "No Gray Area" Principle

Traditional Approach:
+-- Compiles                          (green)
+-- Compiles with warnings            (gray area - technical debt zone)
+-- Doesn't compile                   (red)

EK9 Approach:
+-- Compiles (passed ALL checks)      (green)
+-- Doesn't compile                   (red)

No gray area. No accumulating debt.
    

Implemented Quality Metrics

EK9 currently enforces four categories of quality metrics. Each violation produces a compile-time error with detailed guidance on how to fix the issue.

4.1 Complexity Limits

Complexity is measured using cyclomatic complexity (McCabe, 1976). High complexity indicates code that is difficult to understand, test, and maintain.

Error CodeMetricThresholdDescription
E11010 Cyclomatic Complexity Function: 45, Class: 500 Too many decision points (if/switch/loops)
E11011 Nesting Depth Max: 6 levels Absolute structural limit for nested control structures
E11021 Cognitive Complexity Max: 35 points Guards (<-) add +1 penalty, cost multiplied by depth
E11013 Expression Complexity Max: 15 points Nested coalescing operators (??, ?:)
E11022 Class Should Be Component ≥4 service fields, 0 data Pure service coordinator should use defines component
E11023 Missing 'by' Delegation ≥70% override, ≥5 methods Manual forwarding should use by delegation
E11024 Hybrid Class-Component 1+ by, ≥3 services Mixed responsibilities should be split
E11025 Excessive Mixed Responsibilities ≥3 services AND ≥3 data Blob/God Class - split into component + data class

What adds complexity: Each if, switch case, while, for loop, Boolean operator (and, or), exception handler, and stream pipeline stage adds to the complexity score.

Cognitive Complexity (E11021): Based on SonarQube's Cognitive Complexity metric, adapted for EK9. Formula: (base_cost + guard_penalty) × nesting_depth. Guard expressions (<-) pack declaration + conditional check into one line, so they add +1 cognitive penalty. A 6-level guard chain exceeds the threshold (42 > 35) while 6 simple ifs pass (21 < 35). This catches code that's "hard to understand" before E11011's structural limit at depth 6.

4.2 Cohesion Metrics (LCOM4)

Cohesion measures how well the methods of a class work together. EK9 uses LCOM4 (Lack of Cohesion of Methods, version 4) from Hitz & Montazeri (1995).

Error CodeConstructThresholdWhat It Means
E11014 Class Max LCOM4: 8 Class has too many unrelated method groups
E11014 Component Max LCOM4: 10 Component coordinates too many concerns

Plain English: If your class has methods that don't share any fields with each other, it's doing too many unrelated things. Split it into focused classes.

Exemptions: Traits, Records, and Functions are exempt from cohesion checks by design — traits have abstract methods (no field access), records focus on data operators, and functions have a single body.

4.3 Coupling Metrics (Efferent Coupling)

Coupling measures how many external types a construct depends on. High coupling creates fragile code that breaks when dependencies change. EK9 tracks efferent coupling (Ce) — the count of external types your construct references.

Error CodeConstructThresholdWhat It Means
E11015 Class Max Ce: 12 Class depends on too many external types
E11015 Component/Service Max Ce: 15 Entry point coordinates too many dependencies
E11015 Trait/Record/Function Max Ce: 8 Simpler constructs should have fewer dependencies

What's tracked: Field types, method parameter types, return types, super classes, implemented traits, and captured variables in dynamic constructs.

What's excluded: Built-in types from org.ek9.lang (Integer, String, List, etc.) are not counted toward coupling — they're part of the language, not external dependencies.

4.4 Module-Level Quality Metrics

Beyond construct-level metrics, EK9 also enforces quality at the module level. These metrics operate across all source files in a module and catch architectural issues that span multiple files.

Module Coupling (E11016)

Counts the number of distinct external modules a module depends on. High module coupling indicates a module that depends on too many other modules, making it fragile and difficult to maintain in isolation.

Error CodeMetricThresholdWhat It Means
E11016 External Module Count Max: 10 Module depends on too many other modules

What's tracked: All type references to constructs defined in other modules (excluding built-in org.ek9.* modules). Includes field types, method parameters, return types, super classes, and implemented traits.

What's excluded: References to org.ek9.lang built-in types are not counted as external dependencies — they're part of the language runtime.

Module Cohesion (E11017)

Measures how well the constructs within a module relate to each other. Uses connected component analysis (similar to LCOM4) to detect modules with many unrelated construct groups that should potentially be split into separate modules.

Error CodeMetricThresholdWhat It Means
E11017 Disconnected Groups Max: 30 groups AND >88% Module has too many unrelated construct groups

How it works: Constructs that reference each other (through field types, method parameters, inheritance, etc.) are connected. Disconnected groups are clusters of constructs with no references between them. Many disconnected groups suggest the module could be split.

Exemptions: Small modules (<60 constructs) are exempt — module cohesion is only meaningful for large modules where fragmentation is a real concern.

Thresholds: Uses a hybrid approach requiring BOTH absolute (>30 groups) AND relative (>88% disconnected) thresholds to be exceeded. This allows legitimate utility modules with many independent constructs while catching truly fragmented modules.

4.5 Inheritance Depth Limits

Deep inheritance hierarchies make code hard to understand because you must trace through many levels to understand behavior. EK9 limits inheritance depth and encourages delegation via the by keyword as an alternative.

Error CodeConstructMax DepthRationale
E11019 Class 4 Standard aggregate
E11019 Trait 4 Interface composition chains
E11019 Component 4 Entry point specialization
E11019 Function 3 Function inheritance is rare
E11019 Record 2 Data-focused, minimal behavior

Better Alternative: Instead of deep inheritance, use composition with the by keyword to delegate behavior:

#!ek9
defines module delegation.example
  defines trait
    Printable
      print() as abstract

  defines class
    ConsolePrinter is Printable
      override print()
        stdout.println("Console output")

    // Instead of: class MyClass extends DeepHierarchy
    // Use delegation:
    MyClass with trait of Printable by printer
      printer as Printable: ConsolePrinter()
      

4.6 Combined Complexity and Size (Novel)

EK9 introduces a novel combined metric that catches the "both moderately high" scenario that passes individual complexity (E11010) and statement count (E11012) limits but represents a maintainability risk.

Research Basis: NASA Software Assurance Technology Center studies explicitly found that modules with both high complexity AND large size have the lowest reliability. Individual limits miss this critical combination.

Formula

combined = (complexity / maxComplexity) × (statements / maxStatements)
threshold = 0.50

This creates a curved boundary — you can be high in one dimension if you're low in the other:

Complexity%Statements%CombinedResult
31/4569%107/15071%0.49✓ passes
32/4571%108/15072%0.51E11020
40/4589%80/15053%0.47✓ passes
45/45100%75/15050%0.50✓ boundary

Why This Approach is Novel

Target: Both metrics below 70% of their limits achieves combined ≤0.49. The product formula naturally encourages balanced reduction — reducing one metric by 15% AND the other by 15% is more effective than reducing one metric by 30% alone.


Purity and Quality Integration

EK9's pure keyword isn't just about functional programming correctness — it enables more accurate quality metrics and better optimization.

How Purity Enables Quality

EK9 implements a three-tier purity model:

  1. Compile-time enforcement: The pure keyword is checked by the compiler
  2. Pragmatic I/O: I/O operations are tracked but allowed in non-pure contexts
  3. Controlled mutation: Mutation is explicit and contained, not hidden

Operator Semantic Constraints

Beyond structural metrics, EK9 enforces semantic constraints on operators at compile-time. This ensures operators behave correctly and consistently across all types. See Operators for the full operator reference.

Return Type Constraints

Each operator category has strict return type requirements:

Operator CategoryOperatorsRequired Return TypeError Code
Comparison <, <=, >, >=, ==, <> Boolean E07520
Comparator <=>, <~> Integer E07550
Is-Set ? Boolean E07520
Hash Code #? Integer E07550
String Conversion $ String E07570
JSON Conversion $$ JSON E07580
Complement/Absolute ~, abs Same as construct type E07410
Promotion #^ Different from construct type E07420

Purity Constraints

Operators are divided into pure (no side effects) and mutating categories:

Defaulting Requirements

When using the default keyword to auto-generate comparison operators, the compiler validates that all required underlying operators exist:

This ensures that defaulted operators have correct semantics — a comparison can only be auto-generated if the type knows how to compare all its parts.


Parameter Safety

EK9 enforces parameter immutability at compile-time, preventing a common source of bugs where function parameters are accidentally modified.

Parameter Count Limits

Functions and methods have a hard limit of 20 parameters. Exceeding this triggers E11010 (Excessive Complexity). Additionally, parameter count contributes to complexity scoring:

This encourages grouping related parameters into records, improving API design.

No Parameter Reassignment

Function and method parameters cannot be reassigned within the function body (E08110). This eliminates bugs where the original parameter value is lost:

#!ek9
@Error: FULL_RESOLUTION: NO_INCOMING_ARGUMENT_REASSIGNMENT
processData()
  -> data as Integer
  <- result as Integer?

  data := data + 1    //Error: cannot reassign parameter
  result: data * 2
#!ek9
processData()
  -> data as Integer
  <- result as Integer?

  adjusted <- data + 1    //Create new variable instead
  result: adjusted * 2

Why This Matters


Impact on AI-Assisted Development

As AI coding assistants become more prevalent, EK9's compile-time quality enforcement provides unique benefits for human-AI collaboration.

The AI Code Quality Problem

AI coding assistants (like GitHub Copilot, Claude, and others) can generate code quickly, but often produce code with quality issues:

How EK9 Helps

EK9's compiler provides immediate feedback that helps both humans and AI improve:

Enterprise Benefits

For enterprise teams adopting AI coding assistants, EK9 provides crucial safeguards:


Implementation Roadmap

EK9's quality enforcement is being implemented in phases:

Completed (2024-2025)

Planned (2026)

Future (2027+)

Deferred (Requires IR Generation Completion)


Summary

EK9's compile-time quality enforcement represents a fundamental shift in how programming languages approach code quality. By making quality mandatory rather than optional, EK9 eliminates technical debt at its source.

The EK9 Guarantee: If your code compiles, it has met rigorous quality standards for complexity, cohesion, coupling, and inheritance depth. There is no gray area, no accumulated warnings, and no technical debt.

Next Steps