How do I verify AI-generated EK9 code?

← What AI Gets Wrong About EK9 · Ref: Q281

The EK9 compiler catches ALL common AI mistakes. Three-step verification:

STEP 1: COMPILE — Run 'ek9 -c file.ek9'. Catches syntax, types, operators, code flow.

STEP 2: FIX ERRORS — Use 'ek9 -h String', 'ek9 -h List' for correct APIs. Use 'ek9 -q "topic"' for patterns.

STEP 3: TEST — Use @Test and assert, run 'ek9 -t file.ek9' for logic errors.

COMMON AI FIXES

  'return x' -> '<- rtn as Type: x'
  'break' -> 'head N' in stream
  'if x != null' -> 'if x <- expr()' (guard)
  'extends List' -> delegation
  '.toString()' -> '$' operator
  lambda -> dynamic function

See Q274-Q280 for specific AI mistake categories. See Q52 for dynamic functions. See Q115 for dynamic classes. See Q156 for assert.

Example

defines module qa.ai.mistakes.verify

  defines function

    // Declared return — AI would write 'return'
    classify() as pure
      -> score as Integer
      <- rating as String: "average"
      excellentThreshold <- 90
      poorThreshold <- 40
      if score >= excellentThreshold
        rating: "excellent"
      else if score < poorThreshold
        rating: "poor"

    // Pure predicate for stream filter — replaces 'continue'
    isPositive() as pure
      -> number as Integer
      <- positive as Boolean: number > 0

    // Abstract function type — dynamic functions implement these
    transformer() as pure abstract
      -> input as Integer
      <- output as Integer?

  defines trait

    Formatter
      format() as abstract
        -> input as String
        <- rtn as String?

  defines class

    // Composition — AI would write 'extends List of String'
    NameList
      items as List of String: List() of String

      default NameList()

      add()
        -> entry as String
        if entry?
          items += entry

      count() as pure
        <- total as Integer: length items

      allNames() as pure
        <- names as List of String: items + List() of String

      // $ operator — AI would write toString()
      operator $ as pure
        <- rtn as String: `NameList(${count()} names)`

      // ? operator — AI would write isPresent() or isActive()
      override operator ? as pure
        <- rtn as Boolean: items?

  defines program

    VerifyAiCodeDemo()
      stdout <- Stdout()

      // === DECLARED RETURN (not 'return') ===

      stdout.println(`Score 95: ${classify(95)}`)
      stdout.println(`Score 30: ${classify(30)}`)

      // === STREAM PIPELINE (not break/continue) ===

      numbers <- [-2, 5, -1, 8, 0, 3]
      positives <- cat numbers | filter by isPositive | head 2 | collect as List of Integer
      for num in positives
        stdout.println(`Positive: ${num}`)

      // === GUARD EXPRESSION (not null check) ===

      if rating <- classify(75)
        stdout.println(`Rating: ${rating}`)

      // === COMPOSITION (not extends List) ===

      names <- NameList()
      names.add("Alice")
      names.add("Bob")
      stdout.println($names)
      stdout.println(`Count: ${names.count()}`)

      // === GUARDED ASSIGNMENT (not null coalescing) ===

      config <- String()
      config :=? "production"
      stdout.println(`Config: ${config}`)

      // === ? OPERATOR (not isPresent/isActive) ===

      stdout.println(`Names set: ${names?}`)

      // === DYNAMIC FUNCTION (not lambda '(x) -> x + x') ===

      doubler <- () is transformer as pure function
        output:=? input + input

      testInput <- 21
      stdout.println(`Doubled: ${doubler(testInput)}`)

      // === UNNAMED DYNAMIC CLASS (not 'new Interface() { }') ===

      tag <- ">>>"
      fmtHandler <- (tag) with trait of Formatter as class
        override format()
          -> input as String
          <- rtn as String: `${tag} ${input}`
        default operator ?

      stdout.println(fmtHandler.format("hello"))

      // === NAMED DYNAMIC CLASS (not inline 'class Pair { }') ===

      userName <- "Carol"
      userAge <- 30
      person <- PersonInfo(label: userName, personAge: userAge) as class
        describe() as pure
          <- rtn as String: `${label} age ${personAge}`
        operator $ as pure
          <- rtn as String: describe()
        default operator ?

      stdout.println($person)

      // === BARE NOUN ACCESSOR (not getCount/getNames) ===

      allItems <- names.allNames()
      for item in allItems
        stdout.println(`  Name: ${item}`)

    // === STEP 6: WRITE TESTS TO VERIFY AI LOGIC ===

    @Test
    VerifyClassify()
      assert classify(95) == "excellent"
      assert classify(30) == "poor"
      assert classify(60) == "average"

    @Test
    VerifyNameList()
      names <- NameList()
      names.add("Alice")
      names.add("Bob")
      expectedCount <- 2
      assert names.count() == expectedCount
      assert names?

    @Test
    VerifyDynamicFunction()
      doubler <- () is transformer as pure function
        output:=? input + input
      testInput <- 21
      expectedResult <- 42
      assert doubler(testInput) == expectedResult

    @Test
    VerifyDynamicClass()
      tag <- ">>>"
      fmtHandler <- (tag) with trait of Formatter as class
        override format()
          -> input as String
          <- rtn as String: `${tag} ${input}`
        default operator ?
      expectedOutput <- ">>> test"
      assert fmtHandler.format("test") == expectedOutput

Common mistakes

E50001 — Renaming the variable means later references to 'names' become unresolved, triggering E50001. Variable names must be consistent. See ek9 -h E50001 for details.

Incorrect:

namesXYZ <- NameList()

Correct:

names <- NameList()

E50001 — Renaming the variable means later references to 'config' become unresolved, triggering E50001. Variable names must be consistent. See ek9 -h E50001 for details.

Incorrect:

configXYZ <- String()

Correct:

config <- String()

E50001 — Renaming the variable means later references to 'tag' become unresolved, triggering E50001. Variable names must be consistent. See ek9 -h E50001 for details.

Incorrect:

tagXYZ <- ">>>"

Correct:

tag <- ">>>"

E05120 — Methods implementing trait abstracts in a dynamic class must use 'override' keyword. Without it the method shadows the parent rather than implementing it. See ek9 -h E05120 for details.

Incorrect:

format()
          -> input as String
          <- rtn as String: `${tag} ${input}`

Correct:

override format()
          -> input as String
          <- rtn as String: `${tag} ${input}`
Other ways to ask this
  • How do I check if AI-generated EK9 code is correct?
  • What is the workflow for validating AI EK9 output?
  • How do I use the compiler to review AI code?

Coming from another language?

Java/Python/JS: no equivalent compile-time AI code verification. EK9: compiler catches ALL common AI mistakes with specific error codes, built-in help and Q&A system for correct patterns.

Keywords: check, correct, hallucination, mistake, validate, review, trait, assistant, compile, anonymous, class, tool, error, lambda, pitfall, code, dynamic, verify, common-error, function, ai, capture