Question: Why can't I use a function type to parameterize a generic that calls constructors?

What is E06110 CONSTRUCTOR_WITH_FUNCTION_IN_GENERIC?

Why does EK9 reject my generic when I parameterize it with a function?

What are the limitations of using functions with generic types?

Answer:
EK9 generics discover implicit requirements from their bodies. If a generic uses 'T()' (constructor) or 'arg0 <=> arg1' (comparator), those become requirements on the parameterizing type. Functions cannot satisfy constructor or comparator requirements, so parameterizing such generics with a function triggers E06110.

IMPLICIT CONTRACT DISCOVERY
When you write:
  Holder of type T
    createNew() <- rtn as T: T()      // Requires T has a constructor
    compare() <- rtn as Integer: a <=> b  // Requires T has <=>
The compiler discovers that T must have a constructor and a comparator.

FUNCTION LIMITATIONS
Functions cannot be constructed with 'T()' — they are not classes. Functions cannot be compared with '<=>'. So a function can only parameterize generics that use minimal capabilities like '?' (isSet).

CONTAINER-STYLE GENERICS WORK
A generic that only checks 'arg0?' and 'arg1?' works with functions — like List or Optional. These are container-style generics that just hold values.

THIS EXAMPLE
Shows a container-style generic (SafeHolder) that works with both classes and functions, alongside a concrete class (Counter) that satisfies constructor requirements.

See Q646 for type inference limits. See Q707 for Consumer/Acceptor. See Q58 for generic functions.

defines module qa.generics.function.in.generic

  defines function

    <?-
      Abstract function type for use as a delegate/generic parameter.
    -?>
    CheckFn as abstract
      -> arg0 as Integer
      <- rtn as Boolean?

    IsPositive() is CheckFn
      -> arg0 as Integer
      <- rtn as Boolean: arg0 > 0

  defines class

    Counter
      count <- 0

      default Counter()

      Counter()
        -> initial as Integer
        count :=: initial

      increment()
        count += 1

      value()
        <- rtn as Integer: Integer(count)

      default operator ?

    <?-
      A container-style generic — only uses '?' operator.
      This works with BOTH classes AND functions.
    -?>
    SafeHolder of type T

      default SafeHolder()

      default SafeHolder()
        -> arg0 as T

      check()
        ->
          arg0 as T
          arg1 as T
        <-
          rtn as Boolean: arg0? and arg1?

    <?-
      Generic that uses T() constructor — NOT safe for functions.
    -?>
    ConstructingHolder of type T
      default ConstructingHolder()
      default ConstructingHolder()
        -> arg0 as T
      check()
        ->
          arg0 as T
          arg1 as T
        <-
          rtn as Boolean: arg0? and arg1?
      createNew()
        <- rtn as T: T()

    <?-
      Generic that uses <=> comparator — NOT safe for functions.
    -?>
    ComparingHolder of type T
      default ComparingHolder()
      default ComparingHolder()
        -> arg0 as T
      check()
        ->
          arg0 as T
          arg1 as T
        <-
          rtn as Boolean: arg0? and arg1?
      compare()
        ->
          arg0 as T
          arg1 as T
        <-
          rtn as Integer: arg0 <=> arg1

  defines program

    GenericFunctionDemo()
      stdout <- Stdout()

      //Functions work with container-style generics
      holder <- SafeHolder() of CheckFn
      result <- holder.check(IsPositive, IsPositive)
      stdout.println(`Function holder check: ${result}`)

      //Classes work with any generic
      counterHolder <- SafeHolder() of Counter
      classResult <- counterHolder.check(Counter(), Counter(5))
      stdout.println(`Counter holder check: ${classResult}`)

Java: type erasure means generic constraint violations appear as ClassCastExceptions at runtime. C++: templates check at instantiation with poor diagnostics. Rust: requires explicit trait bounds ('T: Ord'). EK9: discovers implicit requirements from generic body and validates at parameterization site with specific error codes.

E06110 comparator constraint constructor container function generic implicit isSet parameterize

function in generic
E06110
implicit requirements

holder <- ConstructingHolder() of CheckFn

Explanation: ConstructingHolder uses 'T()' in its body, requiring a constructor. Functions cannot be constructed. Use a container-style generic that only uses '?' (isSet) with functions. See ek9 -h E06110 for details.

Explanation: ComparingHolder uses 'arg0 <=> arg1' in its body. Functions cannot be compared. Use a generic that only checks isSet with functions. See ek9 -h E06120 for details.


Question: Why can't I use 'default operator <=>' on a record with a function delegate field?

What is E07210 FUNCTION_DELEGATE_WITH_DEFAULT_OPERATORS?

Why does EK9 reject default comparator on my record with a delegate?

How do I compare records that contain function delegate fields?

Answer:
EK9 prevents 'default operator <=>' (and similar auto-generated comparison operators) on records that contain function delegate fields. The reason: how do you meaningfully compare two function references? Reference equality is almost never useful.

THE PROBLEM
When you write 'default operator <=>' the compiler auto-generates comparison by comparing each field. For String or Integer fields this is clear. But for a function delegate field, what does 'delegate1 <=> delegate2' mean? There is no meaningful default comparison.

WHAT STILL WORKS
- 'default operator ?' (isSet) — always valid, checks if the delegate is assigned
- Explicit operator implementation — you can write your own comparison that ignores the delegate
- Records without delegate fields — all default operators work normally

THIS EXAMPLE
Class EventHandler wraps a function delegate with an explicit comparator. SimpleRecord (no delegates) uses all default operators freely.

See Q116 for default operators. See Q96 for operator overview. See Q98 for record operators.

defines module qa.classesandoop.delegate.defaultoperator

  defines function

    <?-
      Abstract function type used as a delegate.
    -?>
    Handler as abstract
      -> event as String
      <- rtn as Boolean?

    LogHandler() is Handler
      -> event as String
      <- rtn as Boolean: event?

  defines class

    <?-
      Class wrapping a function delegate field.
      Uses explicit comparator since default comparator
      would not know how to compare function references.
    -?>
    EventHandler
      eventName <- String()
      handler as Handler?

      default private EventHandler()

      EventHandler()
        ->
          n as String
          h as Handler
        eventName :=: n
        handler := h

      fire()
        <- rtn as Boolean: handler(eventName)

      //Explicit comparator — compares by name, ignoring the delegate
      operator <=> as pure
        -> arg0 as EventHandler
        <- rtn as Integer: eventName <=> arg0.eventName

      override operator ? as pure
        <- rtn as Boolean: eventName? and handler?

  defines record

    <?-
      Record without delegates — all default operators work fine.
    -?>
    SimpleRecord
      label <- "none"

      SimpleRecord()
        -> l as String
        label :=: l

      operator <=> as pure
        -> arg0 as SimpleRecord
        <- rtn as Integer: label <=> arg0.label

      default operator

  defines program

    DelegateDemo()
      stdout <- Stdout()

      eh1 <- EventHandler("click", LogHandler)
      eh2 <- EventHandler("submit", LogHandler)

      if eh1?
        comparison <- eh1 <=> eh2
        stdout.println(`Comparison: ${comparison}`)
        stdout.println(`Fire: ${eh1.fire()}`)

      simple1 <- SimpleRecord("alpha")
      simple2 <- SimpleRecord("beta")
      if simple1?
        simpleResult <- simple1 <=> simple2
        stdout.println(`Simple: ${simpleResult}`)

Java: records with functional interface fields auto-generate equals/hashCode comparing by identity — usually meaningless. Kotlin: data classes with lambda fields use reference equality for lambdas. C#: records include delegates in equality using invocation list — fragile and surprising. EK9: rejects default comparison for delegate-containing records at compile time.

E07210 comparator comparison default delegate field function isSet operator record

function delegate operators
E07210
default operator limits

Explanation: Record has a function delegate field — 'default operator <=>' cannot be auto-generated because comparing function references has no meaningful semantics. Use 'default operator ?' (always valid) or implement comparison explicitly. See ek9 -h E07210 for details.

Explanation: Cannot auto-generate all default operators for records with delegates. 'default operator' would include comparators which cannot compare function references. Implement operators explicitly. See ek9 -h E07210 for details.


Question: Why can't I provide a signature or body when using 'default operator' in EK9?

What is E07230 DEFAULT_WITH_OPERATOR_SIGNATURE?

Why does 'default operator >= as pure' fail to compile?

What does 'default' mean on an operator and why can't I add parameters?

Answer:
The 'default' keyword on an operator means 'compiler, auto-generate this operator from the existing fields and prerequisite operators'. Adding a signature, modifiers like 'as pure', parameters, or a body contradicts this — you are simultaneously asking the compiler to generate it AND manually specifying it.

THE RULE
- 'default operator <=>' — valid, compiler generates comparator
- 'default operator' — valid, compiler generates ALL supported operators
- 'default operator >= as pure' — ERROR E07230, contradictory
- 'default operator ? as pure <- rtn as Boolean: x?' — ERROR E07230, contradictory

WHY IT IS AN ERROR
If you want auto-generation, write 'default operator <name>' with nothing else. If you want a custom implementation, write the full operator without 'default'. Mixing the two indicates a misunderstanding of what 'default' means.

PREREQUISITE OPERATORS
Some default operators require other operators to exist first. For example, 'default operator >=' needs the comparator '<=>'. You can provide '<=>'' explicitly and default the rest.

THIS EXAMPLE
The Shape record provides an explicit comparator, then uses 'default operator' to auto-generate all remaining supported operators (>=, <=, >, <, ==, <>, $, #?).

See Q116 for default operator overview. See Q96 for operator semantics. See Q774 for abstract constructor.

defines module qa.classesandoop.default.operator.signature

  defines record

    Shape
      name <- String()
      sides <- 0

      Shape()
        ->
          n as String
          s as Integer
        name :=: n
        sides :=: s

      //Explicit comparator — prerequisite for defaulting >=, <=, etc.
      operator <=> as pure
        -> arg0 as Shape
        <- rtn as Integer: sides <=> arg0.sides

      //Auto-generate ALL remaining supported operators
      default operator

  defines class

    Config
      label <- "default"
      priority <- 0

      default Config()

      Config()
        ->
          l as String
          p as Integer
        label :=: l
        priority :=: p

      describe()
        <- rtn as String: `${label} (priority ${priority})`

      //Explicit comparator
      operator <=> as pure
        -> arg0 as Config
        <- rtn as Integer: priority <=> arg0.priority

      //Selective default — just the isSet operator
      default operator ?

  defines program

    DefaultOperatorDemo()
      stdout <- Stdout()

      triangle <- Shape("triangle", 3)
      square <- Shape("square", 4)

      if triangle?
        stdout.println(`Triangle >= Square: ${triangle >= square}`)
        stdout.println(`Triangle == Square: ${triangle == square}`)
        stdout.println("Triangle $: " + $triangle)

      c1 <- Config("high", 10)
      c2 <- Config("low", 1)
      if c1?
        stdout.println(c1.describe())
        stdout.println(`c1 > c2: ${c1 <=> c2 > 0}`)

Java: no operator overloading or auto-generation. Kotlin: data class generates all-or-nothing. Rust: #[derive(PartialEq, Hash)] is selective auto-generation. EK9: 'default operator' is selective, but 'default' and manual specification are mutually exclusive — prevents contradictory declarations.

E07230 auto-generate body contradictory default modifier operator prerequisite pure signature

default operator
E07230
auto-generation rules

      //Auto-generate ALL remaining supported operators
      default operator >= as pure
        -> arg0 as Shape
        <- rtn as Boolean: false

Explanation: Cannot provide a signature or body with 'default operator'. The keyword 'default' means the compiler generates it. Either remove 'default' and write the operator manually, or remove the signature/body. See ek9 -h E07230 for details.

      default operator ? as pure
        <- rtn as Boolean: name?

Explanation: Providing 'as pure' modifier and a body with 'default' is contradictory. Use 'default operator ?' alone for auto-generation, or remove 'default' and write the full operator. See ek9 -h E07230 for details.


Question: Why can't I use compound assignment like '+=' in a switch pre-flow in EK9?

What is E07340 PRE_FLOW_SYMBOL_NOT_RESOLVED?

Why does 'switch record.prop += 3' fail in EK9?

What assignment forms are valid in switch pre-flow?

Answer:
EK9 switch pre-flow only accepts declarations ('<-') or simple assignments (':='). Compound assignment operators like '+=' on property access are rejected because the control value is ambiguous.

See Q69 for multi-case switch. See Q144 for no break/continue/return.

defines module qa.controlflow.switch.preflow

  defines record
    Scoring
      prop1 <- 0

      Scoring()
        -> initial as Integer
        prop1 :=: initial

      override operator ? as pure
        <- rtn as Boolean: prop1?

  defines function

    classifyScore()
      <- rtn as String: String()

      scoring <- Scoring(5)
      result <- 0

      switch controlScore <- scoring.prop1 + 3 with controlScore
        case > 1
          result += 6
        default
          result += 10

      rtn: $result

  defines program

    SwitchPreFlowDemo()
      stdout <- Stdout()
      stdout.println(classifyScore())

Java: switch has no pre-flow. C: assignment in switch is bad practice. Kotlin: when has no pre-flow. EK9: pre-flow restricted to declarations and simple assignments.

E07340 assignment compound declaration pre-flow switch

switch pre-flow
E07340
compound assignment

Explanation: Compound assignment on a property in switch pre-flow has ambiguous control semantics. Use a declaration instead. See ek9 -h E07340 for details.


Question: Can I use a guard (including '?=') inside a switch or loop expression in EK9?

Do guards work in switch/for/while/try expressions?

What does 'result <- switch temp ?= getValue() with temp' do?

Why does a guard in an expression need an initialised return (E08050)?

Answer:
Yes. A body-skipping guard ('<-' declaration, '?=' guarded assignment, ':=?' assign-if-unset) works in an expression-form switch/for/while/do-while/try, just as in statement form. The guard gates the whole construct: if the guarded value is unset the body is skipped, and the left-hand side takes the returning variable's INITIAL value - 'the initialiser is the guard's else'.

BECAUSE OF THAT, THE RETURN MUST BE INITIALISED
Declare the return with an initial value ('<- rtn as T: default'). If you declare it uninitialised ('<- rtn as T?') and set it only inside the (skippable) body, the compiler rejects it with E08050 RETURN_NOT_ALWAYS_INITIALISED, because the skip path would leave the LHS unset.

THIS EXAMPLE
A switch expression with a '?=' guard and an initialised return. The guard sets 'temperature', the switch runs, and 'resultText' gets a case value; had the guard left 'temperature' unset, 'resultText' would be the initial "Unknown".

See Q759 for guard patterns. See Q69 for multi-case switch.

defines module qa.controlflow.guard.expression

  defines function

    currentTemperature() as pure
      -> country as String
      <- temperature as Integer?

      if country == "GB"
        temperature :=? 18
      else if country == "DE"
        temperature :=? 35
      else
        temperature :=? 25

  defines program

    GuardDemo()
      stdout <- Stdout()

      //Valid: a '?=' guard in a switch expression. The guard gates the switch; if 'temperature' were left
      //unset the body would be skipped and 'resultText' would take the return's initial value ("Unknown").
      temperature as Integer?
      resultText <- switch temperature ?= currentTemperature("GB") with temperature
        <- result as String: "Unknown"
        case < 12
          result: "Cold"
        case < 25
          result: "Moderate"
        default
          result: "Warm"

      stdout.println(resultText)

Kotlin 'when' and Rust 'match' are expressions but have no guard-gating pre-flow. EK9 unifies it: the same guard syntax works in statement AND expression forms, and the mandatory return initialiser is the value the LHS receives when the guard skips.

E08050
conditional
expression
guard
guarded assignment
initialised return
switch

guard in expression
return must be initialised
E08050

Explanation: In an expression form, a guard can skip the body, so the return must be initialised at declaration. Give it a default ('<- result as String: "Unknown"'); an uninitialised '<- result as String?' set only in the body is E08050 RETURN_NOT_ALWAYS_INITIALISED.


Question: Why can't I use 'with application of' on a regular class method in EK9?

What is E07360 APPLICATION_SELECTION_INVALID?

Where can I use 'with application of' in EK9?

How does application selection work in EK9 programs?

Answer:
The 'with application of' syntax is only valid on programs — it tells the EK9 runtime which application context to inject dependencies from. Using it on a regular class method is an error because class methods do not participate in application-level dependency injection.

THE RULE
- Programs CAN use 'with application of <name>' to select a DI context
- Classes, records, functions, and components CANNOT use this syntax
- Application selection is a program-level concern, not a method-level concern

WHY ONLY PROGRAMS
Programs are entry points — they are the top of the dependency injection graph. The 'with application of' annotation tells the runtime which registered application provides the component bindings. Regular methods receive their dependencies through constructor injection or component fields, not through application selection.

THIS EXAMPLE
Shows a program using 'with application of' to select an application context. The Logger component receives its dependency through the DI container, not through application selection on methods.

See Q111 for components. See Q227 for compile-time DI. See Q231 for program-application linking.

defines module qa.classesandoop.application.selection

  defines component

    Logger
      prefix <- "INFO"

      default Logger()

      Logger()
        -> p as String
        prefix :=: p

      log()
        -> message as String
        stdout <- Stdout()
        stdout.println(`[${prefix}] ${message}`)

      default operator ?

  defines class

    Processor
      name <- "default"

      default Processor()

      Processor()
        -> n as String
        name :=: n

      process()
        <- rtn as String: `Processed by ${name}`

      default operator ?

  defines program

    <?-
      Programs are entry points and CAN use 'with application of'.
      This is where DI context selection belongs.
    -?>
    ProcessorDemo()
      stdout <- Stdout()

      processor <- Processor("main")
      if processor?
        stdout.println(processor.process())

      logger <- Logger("DEBUG")
      if logger?
        logger.log("Application started")

Java Spring: @SpringBootApplication on the main class, not on methods. Python Django: DJANGO_SETTINGS_MODULE at application level. Rust: no DI framework in language. Kotlin: Dagger @Component on application class. Go: wire at application level. EK9: 'with application of' on programs only — class methods use constructor injection.

E07360 application component context dependency entry injection method program selection

application selection
E07360
program-level DI

      process() with application of myApp
        <- rtn as String: `Processed by ${name}`

Explanation: The 'with application of' syntax is only valid on programs, not on class methods. Programs are entry points for DI. Class methods receive dependencies through constructor injection. See ek9 -h E07360 for details.

      log()
        -> message as String

      log() with application of myApp
        -> message as String

Explanation: 'with application of' cannot be used on component methods. Application selection belongs on programs only. See ek9 -h E07360 for details.


Question: Why must the promote operator #^ return a different type than the class?

What triggers E07420 MUST_NOT_RETURN_SAME_TYPE?

Why does my promote operator fail with same type error?

How do I correctly implement the #^ promote operator in EK9?

Answer:
The promote operator #^ converts an object to a DIFFERENT type. Returning the same type as the enclosing class is not promotion — it is a copy or identity, which is meaningless.

WHAT PROMOTE DOES
Promotion converts one type to another:
  Temperature -> String (displaying degrees)
  Distance -> Float (extracting raw measurement)
  Score -> Integer (extracting numeric score)

CORRECT PATTERN
  operator #^ as pure
    <- rtn as String: `${degrees} degrees`
The return type (String) differs from the class (Temperature).

INCORRECT PATTERN
  operator #^ as pure
    <- rtn as C5: this
Returning the SAME type (C5) from #^ on class C5 triggers E07420. This is not promotion.

USAGE
  reading <- Temperature(98.6)
  promoted <- #^reading  // promoted is now a String

See Q238 for operator overview. See Q242 for conversion operators.

defines module qa.operators.promote.different.type

  defines class

    <?-
      Temperature with promote operator returning String (a different type).
      This is the correct pattern for promotion.
    -?>
    Temperature
      degrees <- 0.0

      Temperature()
        -> d as Float
        degrees :=: d

      //Promote to String — returns DIFFERENT type (correct)
      operator #^ as pure
        <- rtn as String: `${degrees} degrees`

      default operator ?

  defines program

    PromoteDemo()
      stdout <- Stdout()
      reading <- Temperature(98.6)
      promoted <- #^reading
      stdout.println(promoted)

Java: No promote operator. Implicit conversions via widening (int to long). Explicit casts for narrowing. Python: No operator-based promotion; uses __int__(), __float__(), __str__() dunder methods with no return type enforcement. Rust: From/Into traits enforce different types by design. Kotlin: toInt(), toString() methods with no operator syntax. EK9: #^ operator with compile-time enforcement that return type differs from enclosing class.

#^ E07420 conversion different operator promote return type

      operator #^ as pure
        <- rtn as Temperature: this

Explanation: The promote operator #^ must return a DIFFERENT type than the enclosing class. Returning Temperature from a Temperature class is identity, not promotion. Return String, Integer, Float, or another distinct type. See ek9 -h E07420 for details.


Question: Why does passing the wrong type to a function cause E06270 in EK9?

What triggers E06270 PARAMETER_MISMATCH?

Why can't I pass Integer where String is expected in EK9?

How do I convert types explicitly in EK9?

Answer:
EK9 does NOT auto-convert between incompatible types. Passing an Integer where a String is expected triggers E06270 PARAMETER_MISMATCH.

NO IMPLICIT CONVERSION
Unlike Java (which auto-boxes and calls toString()), EK9 requires explicit type conversion:
  acceptsString(123)     // ERROR E06270 — Integer is not String
  acceptsString($123)    // CORRECT — $ converts Integer to String

THE $ OPERATOR
The $ operator converts any type to its String representation:
  age <- 25
  label <- $age           // "25" as String

INSIDE BACKTICK STRINGS
Use ${expression} for interpolation:
  greeting <- `Age is ${age}`

FUNCTION PARAMETERS MUST MATCH
  showName(name as String) — expects String
  showName("Steve")       — correct
  showName(42)            — ERROR E06270
  showName($42)           — correct (converts to "42")

See Q194 for generic type basics. See Q238 for operator overview.

defines module qa.genericsdeep.parameter.type.mismatch

  defines function

    acceptsString() as pure
      -> phrase as String
      <- rtn as String: phrase

    acceptsInteger() as pure
      -> amount as Integer
      <- rtn as Integer: amount

  defines program

    ParameterTypeDemo()
      stdout <- Stdout()

      // === CORRECT: matching types ===
      greeting <- acceptsString("Hello EK9")
      stdout.println(greeting)

      score <- acceptsInteger(42)
      stdout.println($score)

      // === CORRECT: explicit $ conversion ===
      converted <- acceptsString($score)
      stdout.println(converted)

      // === CORRECT: interpolation inside backticks ===
      message <- `Score is ${score}`
      stdout.println(message)

Java: Auto-boxes primitives and calls toString() implicitly in string concatenation. Integer passed to String parameter causes compile error but string concat works. Python: Dynamically typed, type mismatches caught only at runtime. Rust: No implicit conversions, requires .to_string() or Into trait. Kotlin: Requires explicit .toString(), similar to EK9. EK9: No implicit conversions, uses $ operator for string conversion.

E06270 conversion dollar explicit mismatch parameter string type

parameter type mismatch
E06270
explicit type conversion

Explanation: Integer cannot be implicitly converted to String. Use the $ operator to explicitly convert: $123 produces the String "123". See ek9 -h E06270 for details.


Question: Why can't I instantiate an abstract generic type like Iterator of String?

What triggers E10030 CONSTRUCTOR_USED_ON_ABSTRACT_TYPE?

Why does Iterator() of String fail in EK9?

How do I get an iterator from a collection in EK9?

Answer:
Parameterizing an abstract generic type does NOT make it concrete. Iterator, Supplier, Predicate, Consumer, and other abstract function types remain abstract after parameterization.

WHY IT FAILS
  notAllowed <- Iterator() of String  // ERROR E10030
Iterator is abstract. Adding 'of String' specifies the type parameter but does not provide an implementation. You cannot call a constructor on an abstract type.

CORRECT ALTERNATIVES

1. Get an iterator from a concrete collection:
  names <- List() of String
  names += "Steve"
  iter <- names.iterator()

2. Use a dynamic function for abstract function types:
  greeter <- () is Supplier of String as function (rtn: "Hello")

3. Extend with a concrete implementation:
  Define a class that extends the abstract type and provides method bodies.

THIS APPLIES TO ALL ABSTRACT GENERICS
Iterator, Supplier, Consumer, Producer, Predicate, Acceptor, Function, Comparator, UnaryOperator, and all Bi- variants.

See Q642 for generic constructor inference. See Q194 for generic class basics.

defines module qa.genericsdeep.abstract.generic.instantiation

  defines program

    AbstractGenericDemo()
      stdout <- Stdout()

      // === CORRECT: get iterator from a concrete List ===
      names <- List() of String
      names += "Steve"
      names += "Limb"

      iter <- names.iterator()
      stdout.println(`Iterator obtained: ${iter?}`)

      // === CORRECT: use concrete implementation for abstract function types ===
      names += "EK9"
      stdout.println(`List has ${length names} items`)

Java: Same rule — 'new Iterator<String>()' fails. Java allows anonymous classes: 'new Iterator<String>() { ... }'. Python: abc module catches abstract instantiation at runtime only. Kotlin: Same compile-time enforcement; uses SAM conversions for functional interfaces. Rust: Traits cannot be instantiated, only implemented. EK9: E10030 at compile time for all abstract generic types.

E10030 abstract collection concrete constructor generic instantiation iterator

abstract generic instantiation
E10030
iterator from collection

Explanation: Iterator is abstract. Parameterizing it with 'of String' does not make it concrete. Get an iterator from a concrete collection like List instead. See ek9 -h E10030 for details.


Question: Why does streaming non-function values through call fail with E04040?

What triggers E04040 TYPE_MUST_BE_FUNCTION?

Why can't I use cat [1, 2, 3] | call in EK9?

What types can flow through call in an EK9 stream?

Answer:
The stream call and async operators execute function delegates flowing through the pipeline. If the stream contains non-function values (integers, strings), they cannot be 'called' and the compiler rejects with E04040.

See Q813 for call/async rules.

defines module qa.streams.call.requires.function

  defines function

    getGreeting()
      <- rtn <- "Hello"

    getFarewell()
      <- rtn <- "Goodbye"

  defines class
    StreamSink
      received <- String()
      operator |
        -> item as String
        if item?
          received: String(item)
      override operator ? as pure
        <- rtn as Boolean: received?

  defines function

    StreamCallDemo()
      collector <- StreamSink()
      cat [getGreeting, getFarewell] | call > collector
      require collector?

Java: no built-in call operator. Python: map(func, iterable). EK9: call/async require function delegates as stream elements.

E04040 call delegate function pipeline stream type

Explanation: Stream call requires function delegates, not integer values. See ek9 -h E04040 for details.


Question: Why must functions used with stream call/async return a value?

What triggers E07490 FUNCTION_MUST_RETURN_VALUE?

Why can't I use void functions with call in EK9 streams?

What function signature does stream call require?

Answer:
Functions used with call/async must return a value — the return value becomes the next element downstream. A void function produces nothing.

See Q813 for call/async rules. See Q842 for function type requirement.

defines module qa.streams.function.must.return

  defines function

    getFirstName()
      <- rtn <- "Steve"

    getLastName()
      <- rtn <- "Limb"

  defines class
    StreamSink
      received <- String()
      operator |
        -> item as String
        if item?
          received: String(item)
      override operator ? as pure
        <- rtn as Boolean: received?

  defines function

    StreamReturnDemo()
      collector <- StreamSink()
      cat [getFirstName] | call > collector
      require collector?

Java: Supplier returns T, Runnable returns void. Python: map expects return values. EK9: call/async require supplier-style functions.

E07490 call function pipeline return stream supplier void

    getFirstName()
      <- rtn <- "Steve"

    getFirstName()
      stdout <- Stdout()
      stdout.println("logged")

Explanation: Functions used with stream call must return a value. Void functions produce nothing. See ek9 -h E07490 for details.


Question: Why must functions used with stream call/async take no arguments?

What triggers E06310 REQUIRE_NO_ARGUMENTS?

Why can't I stream functions with parameters through call?

What is the correct function shape for stream call?

Answer:
Functions used with call/async must take ZERO arguments. The stream calls them without parameters.

See Q813 for call/async rules. See Q843 for return requirement.

defines module qa.streams.call.no.arguments

  defines function

    getTimestamp()
      <- rtn <- "2026-03-26"

    getHostname()
      <- rtn <- "ek9-server"

  defines class
    StreamSink
      received <- String()
      operator |
        -> item as String
        if item?
          received: String(item)
      override operator ? as pure
        <- rtn as Boolean: received?

  defines function

    StreamNoArgsDemo()
      collector <- StreamSink()
      cat [getTimestamp] | call > collector
      require collector?

Java: Supplier has get() with no arguments. Python: zero-arg callables. EK9: call/async require zero-argument supplier functions.

E06310 arguments call function pipeline stream supplier zero-arg

    getTimestamp()
      -> inputArg as String
      <- rtn <- "2026-03-26"

Explanation: Functions used with stream call must take no arguments. See ek9 -h E06310 for details.


Question: Why must all EK9 service methods return HTTPResponse?

What triggers E07800 SERVICE_MISSING_RETURN?

Why can't my service method omit a return type?

What return type do EK9 service methods require?

Answer:
ALL EK9 service methods must return HTTPResponse. Services are HTTP endpoints — only HTTPResponse can express status codes, headers, content type, and body.

See Q659 for service return types. See Q684 for URI paths.

defines module qa.webservicesdeep.service.return.httpresponse

  defines service

    HealthEndpoint :/health open

      healthCheck() as GET for :/status
        <- response as HTTPResponse: () with trait HTTPResponse
          override content()
            <- rtn as String: `{"status": "healthy"}`
          override status() as pure
            <- rtn as Integer: 200
          override contentType() as pure
            <- rtn as String: "application/json"
          override cacheControl() as pure
            <- rtn as String: "no-cache"
          override contentLanguage() as pure
            <- rtn as String: "en"
          default operator ?

  defines application

    HealthApp
      register HealthEndpoint()

  defines program

    ServiceReturnDemo()
      stdout <- Stdout()
      stdout.println("Service methods must return HTTPResponse")

Java Spring: controllers return any type. C# ASP.NET: IActionResult or POCO. Go: writes to ResponseWriter. EK9: mandatory HTTPResponse.

E07800 HTTPResponse endpoint return service


Question: Why can't I use Float as a service method parameter in EK9?

What triggers E07760 SERVICE_INCOMPATIBLE_PARAM_TYPE_NON_REQUEST?

What parameter types are valid for EK9 service methods?

Why does EK9 restrict service parameter types?

Answer:
EK9 service method parameters are automatically parsed from HTTP request strings (query params, path params). Only types that can be safely parsed from strings are allowed. Float and Money are excluded because HTTP string representation loses precision.

ALLOWED TYPES
Integer, String, Date, Duration, DateTime, Time, Millisecond — all can be unambiguously parsed from a string.

EXCLUDED TYPES
Float — string representation is lossy (0.1 cannot be exactly represented)
Money — financial precision requires exact decimal parsing, not HTTP string conversion

CORRECT PATTERN
Use Integer for numeric parameters, String for text:
  findById() as GET for :/{userId}
    -> userId as Integer

See Q657 for URI mapping. See Q845 for return type requirement.

defines module qa.webdeep.service.parameter.types

  defines constant

    JSON_TYPE <- "application/json"

  defines service

    <?-
      Service with valid parameter types.
      Parameters are parsed from HTTP request strings.
    -?>
    UserService :/users open

      findById() as GET for :/{userId}
        -> userId as Integer
        <- response as HTTPResponse: (capturedId: userId) with trait HTTPResponse
          override content()
            <- rtn as String: `{"userId": ${capturedId}}`
          override status() as pure
            <- rtn as Integer: 200
          override contentType() as pure
            <- rtn as String: JSON_TYPE
          override cacheControl() as pure
            <- rtn as String: "no-cache"
          override contentLanguage() as pure
            <- rtn as String: "en"
          default operator ?

      findByName() as GET for :/{userName}/profile
        -> userName as String
        <- response as HTTPResponse: (capturedName: userName) with trait HTTPResponse
          override content()
            <- rtn as String: `{"name": "${capturedName}"}`
          override status() as pure
            <- rtn as Integer: 200
          override contentType() as pure
            <- rtn as String: JSON_TYPE
          override cacheControl() as pure
            <- rtn as String: "max-age=60"
          override contentLanguage() as pure
            <- rtn as String: "en"
          default operator ?

  defines application

    UserApp
      register UserService()

  defines program

    ServiceParamDemo()
      stdout <- Stdout()
      stdout.println("Valid service parameter types: Integer, String, Date, Time")
      stdout.println("Invalid: Float (precision loss), Money (requires exact decimal)")

Java Spring: @RequestParam binds to any type with a converter — no compile-time restriction. C# ASP.NET: model binding to complex types at runtime. Go: manual string parsing from http.Request. Python Flask: parameter converters registered at runtime. EK9: compile-time restriction to safely-parseable types prevents silent precision loss.

E07760 Float HTTP Integer parameter parse service type

      findByPrice() as GET for :/{price}
        -> price as Float

Explanation: Float is not a valid service parameter type. HTTP string representation loses floating-point precision. Use Integer or String instead, and parse within the method if needed. See ek9 -h E07760 for details.


Question: Where can the sanitized modifier be used in EK9?

What is E07920 in EK9?
Can I mark a field as sanitized?
Why can only parameters be sanitized?
Where is sanitized valid in EK9?

Answer:
The 'sanitized' modifier can only be applied to incoming function or method parameters. Fields, return values, and local variables cannot be marked as sanitized.

WHY ONLY PARAMETERS
Sanitization is a boundary concern. Input enters the system through function and method parameters. Once input has been sanitized at the boundary, the sanitized value can be stored normally. Marking fields or locals as sanitized would be meaningless because they are already inside the trusted boundary.

CORRECT PATTERN
Apply sanitized to the incoming parameter, then store the result:
  processInput() as pure
    -> userInput as sanitized String
    <- rtn as String: userInput

INCORRECT PATTERNS
- Field: name as sanitized String (E07920)
- Return: <- rtn as sanitized String (E07920)
- Local: cleaned as sanitized String (E07920)

See Q844 for sanitized overview. See Q845 for sanitized with records.

defines module qa.sanitizeddeep.parameter.only

  defines function

    <?-
      Correct use of sanitized on an incoming parameter.
      The sanitized value is returned as a normal String.
    -?>
    processInput() as pure
      -> userInput as sanitized String
      <- rtn as String: userInput

  defines program

    SanitizedDemo()
      stdout <- Stdout()

      cleaned <- processInput("hello<script>")
      stdout.println(cleaned)

Java: no language-level sanitization (relies on libraries like OWASP). Python: no sanitization concept. Rust: no built-in sanitization. Go: no sanitization. EK9: compile-time sanitized modifier on parameters only, E07920 if misplaced.

E07920 boundary field input local parameter return sanitized security validation

    SomeClass
      name as sanitized String?

Explanation: The sanitized modifier can only appear on incoming function or method parameters. Fields cannot be sanitized because sanitization is a boundary concern. See ek9 -h E07920 for details.


Question: Can I assign an abstract function as a delegate in EK9?

Why can I not use an abstract function as a delegate?

How do I assign a function reference in EK9?

What is the correct way to delegate to a function?

Answer:
You cannot assign an abstract function reference as a delegate. Abstract functions have no implementation body, so there is nothing to execute. You must assign a concrete function that provides an actual implementation.

WHY ABSTRACT FUNCTIONS CANNOT BE DELEGATES
A delegate is a callable reference. Abstract functions declare a signature but have no body. Assigning one would create a delegate that cannot be called, which is a compile-time error rather than a runtime failure.

CORRECT PATTERN
Define an abstract function, implement it with a concrete subtype, and assign the concrete version:
  Transformer as abstract
    -> input as String
    <- rtn as String?
  UpperTransformer() is Transformer
    -> input as String
    <- rtn as String: input.upperCase()
  handler as Transformer: UpperTransformer

INCORRECT PATTERN
  handler as Transformer: Transformer  // E50070: abstract, no body

See Q100 for function basics. See Q102 for function composition. See Q106 for higher-order functions.

defines module qa.functions.abstract.assignment

  defines function

    <?-
      Abstract function declaring the contract.
      Cannot be used directly as a delegate.
    -?>
    Transformer as abstract
      -> input as String
      <- rtn as String?

    <?-
      Concrete implementation of Transformer.
      This can be assigned as a delegate.
    -?>
    UpperTransformer() is Transformer
      -> input as String
      <- rtn as String: input.upperCase()

  defines program

    AbstractFunctionDemo()
      stdout <- Stdout()

      //Correct: assign concrete function
      handler as Transformer: UpperTransformer
      if handler?
        stdout.println(handler("hello"))

Java: abstract classes cannot be instantiated but interfaces can be lambdas. Python: ABCMeta prevents instantiation at runtime. Kotlin: abstract functions cannot be referenced directly. Rust: trait objects require concrete implementations. EK9: E50070 prevents assigning abstract functions as delegates at compile time.

E50070 abstract assignment callable concrete delegate function implementation reference

Explanation: Abstract functions have no body and cannot be assigned as delegates. Use a concrete implementation instead. See ek9 -h E50070 for details.


Question: Why can't a dispatcher see a private handler method in a superclass?

What triggers E05180 DISPATCHER_PRIVATE_IN_SUPER?

Why must dispatcher handler methods be protected or public?

How do I fix private dispatcher handler visibility?

Answer:
When a subclass has a dispatcher, it searches the superclass for matching handler methods. Private methods in the superclass are invisible. Use protected instead.

See Q616 for dispatcher ambiguity. See Q621 for dispatch rules.

defines module qa.dispatcher.private.super

  defines class

    BaseHandler as open

      protected process()
        -> arg0 as Integer
        require arg0?

      default operator ?

    SubDispatcher extends BaseHandler

      process() as dispatcher
        -> arg0 as Any
        require arg0?

      runDemo()
        this.process(42)

      default operator ?

  defines function

    DispatcherDemo()
      handler <- SubDispatcher()
      handler.runDemo()
      require handler?

Java: Visitor pattern requires public. C#: dynamic dispatch ignores private. EK9: compile-time error if dispatcher handler is private in super.

E05180 dispatcher handler private protected super

      private process()
        -> arg0 as Integer
        require arg0?

Explanation: Private methods in a superclass are invisible to subclass dispatchers. Use protected. See ek9 -h E05180 for details.


Question: Can an abstract class appear in a trait's allow only list?

Why must allow only list concrete classes?

Answer:
A trait's 'allow only' list must contain only concrete classes. Abstract classes cannot be instantiated, so listing them in 'allow only' is meaningless and raises E05250.

WHY ONLY CONCRETE CLASSES
The 'allow only' mechanism restricts which classes can implement a trait. Since abstract classes cannot be instantiated directly, allowing them would create a gap: any concrete subclass of that abstract class could implement the trait without being explicitly listed. This defeats the purpose of sealing.

CORRECT PATTERN
List only concrete, instantiable classes:
  Workable allow only FastWorker, SlowWorker
    execute() as abstract
      <- rtn as String?

INCORRECT PATTERN
  Workable allow only AbstractHelper, ConcreteWorker  // E05250

See Q130 for trait basics. See Q132 for sealed types. See Q134 for allow only patterns.

defines module qa.sealed.allow.only.concrete

  defines class

    <?-
      Abstract helper class — cannot appear in allow only lists.
    -?>
    AbstractHelper as abstract
      execute() as abstract
        <- rtn as String?
      default operator ?

    <?-
      First concrete worker class.
      Can appear in allow only lists because it is concrete.
    -?>
    FastWorker
      execute()
        <- rtn as String: "fast"
      default operator ?

    <?-
      Second concrete worker class.
      Also eligible for allow only lists.
    -?>
    SlowWorker
      execute()
        <- rtn as String: "slow"
      default operator ?

  defines trait

    <?-
      Trait sealed to only FastWorker and SlowWorker.
      No other class can implement this trait.
    -?>
    Workable allow only FastWorker, SlowWorker
      execute() as abstract
        <- rtn as String?

  defines program

    AllowOnlyDemo()
      stdout <- Stdout()

      fast <- FastWorker()
      if fast?
        stdout.println(fast.execute())

Java: sealed interfaces permit abstract classes (different design). Kotlin: sealed interfaces allow abstract implementations. Rust: no sealed traits (crate visibility instead). Scala: sealed traits allow abstract subtypes. EK9: E05250 requires all allow only entries to be concrete classes.

E05250 abstract allow concrete implement instantiate only restrict sealed trait

Workable allow only AbstractHelper, SlowWorker

Explanation: Abstract classes cannot appear in allow only lists because they cannot be instantiated. Only list concrete classes that will implement the trait. See ek9 -h E05250 for details.


Question: Why do references need a module qualifier with :: in EK9?

How do I reference types from other modules?

What is the correct reference syntax in EK9?

Why does a bare type name in references cause an error?

Answer:
References in EK9 must include the module qualifier with the '::' separator. A bare type name without a module path is invalid and raises E01010.

WHY MODULE QUALIFIERS ARE REQUIRED
EK9 uses explicit module references to avoid ambiguity. Two modules might define a type with the same name. The module qualifier ensures the compiler resolves the correct type. Without it, the reference is ambiguous and meaningless.

CORRECT SYNTAX
  references
    some.module::SomeType
    another.module::AnotherType

INCORRECT SYNTAX
  references
    SomeType           // E01010: no module qualifier
    ::SomeType         // E01010: missing module name

See Q10 for module structure. See Q12 for module naming. See Q852 for reserved module names.

defines module qa.syntax.reference.qualifier

  defines function

    <?-
      Simple function demonstrating correct module code.
      References use the format: module.name::SymbolName
    -?>
    formatGreeting() as pure
      -> name as String
      <- rtn as String: `Hello, ${name}!`

  defines program

    ReferenceDemo()
      stdout <- Stdout()

      //Correct references use: module.name::SymbolName
      //Bare names like 'SomeType' without module:: cause E01010
      stdout.println(formatGreeting("Steve"))

Java: import statements use dot notation (java.util.List). Python: import uses dot notation (from os.path import join). Rust: use statements with :: (std::collections::HashMap). Go: import with path strings. EK9: references use module.name::SymbolName with :: separator, E01010 if module qualifier missing.

E01010 import module namespace qualifier reference separator structure symbol syntax

defines module qa.syntax.reference.qualifier

  references
    SomeType

Explanation: References must include the full module path followed by :: and the symbol name. Bare type names without a module qualifier are invalid. See ek9 -h E01010 for details.


Question: Which module names are reserved in EK9?

Can I use org.ek9.lang as my module name?

What namespaces are reserved for built-in types?

Why does my module name cause a compiler error?

Answer:
The org.ek9.lang and org.ek9.math namespaces are reserved for EK9 built-in types. User code must use different module names. Attempting to define a module in these namespaces raises E01020.

WHY RESERVED
Built-in types like String, Integer, Boolean, List, and Dict live in org.ek9.lang. Mathematical types and functions live in org.ek9.math. Allowing user code in these namespaces would create conflicts with built-in type definitions and break the bootstrap process.

RESERVED NAMESPACES
- org.ek9.lang (core types: String, Integer, Boolean, List, Dict, etc.)
- org.ek9.math (mathematical types and functions)

CORRECT MODULE NAMES
- com.mycompany.myproject
- qa.syntax.example
- app.services.auth

INCORRECT MODULE NAMES
- org.ek9.lang (E01020)
- org.ek9.lang.custom (E01020)
- org.ek9.math.extra (E01020)

See Q10 for module structure. See Q851 for reference syntax. See Q14 for package organization.

defines module qa.syntax.reserved.modules

  defines function

    <?-
      Simple function in a user namespace.
      Reserved namespaces org.ek9.lang and org.ek9.math cannot be used.
    -?>
    getVersion() as pure
      <- rtn <- "1.0.0"

  defines program

    ReservedModuleDemo()
      stdout <- Stdout()

      //Reserved namespaces: org.ek9.lang, org.ek9.math
      //User code must choose different module names
      stdout.println(`Version: ${getVersion()}`)

Java: java.lang is reserved by convention (JLS prohibits it). Python: no reserved package names (but shadowing stdlib is a common bug). Rust: std is reserved. Go: no reserved paths (but shadowing stdlib is discouraged). EK9: org.ek9.lang and org.ek9.math are reserved at compile time, E01020 enforced.

E01020 bootstrap built-in conflict module namespace org.ek9.lang org.ek9.math reserved syntax

Explanation: The org.ek9.lang namespace is reserved for EK9 built-in types. Choose a different module name for your code. See ek9 -h E01020 for details.


Question: What happens when parent and child classes have duplicate field names with JSON operator?

Why does EK9 flag duplicate property names in JSON?

Can parent and child have the same field name with operator $$?

How does EK9 prevent ambiguous JSON output?

Answer:
When a class hierarchy uses 'default operator $$' (JSON serialization), property names must be unique across the entire hierarchy. If a parent and child class both have a field with the same name, the JSON output would be ambiguous, raising E02020.

WHY UNIQUE NAMES ARE REQUIRED
JSON keys must be unique within an object. If a parent has field 'label' and a child also has field 'label', the JSON serializer cannot produce valid output. Rather than silently picking one or producing invalid JSON, EK9 catches this at compile time.

CORRECT PATTERN
Use unique field names across the hierarchy:
  BaseConfig as open
    configName <- "default"
  ExtendedConfig extends BaseConfig
    priority <- 0

INCORRECT PATTERN
  BaseConfig as open
    label <- "default"
  ExtendedConfig extends BaseConfig
    label <- "custom"     // E02020: duplicate property

See Q200 for JSON basics. See Q202 for JSON operator patterns. See Q315 for inheritance depth.

defines module qa.quality.duplicate.json.property

  defines class

    <?-
      Base configuration class with configName field.
      Uses default operator for JSON serialization.
    -?>
    BaseConfig as open
      configName <- "default"

      BaseConfig()
        -> cn as String
        configName :=: cn

      operator <=> as pure
        -> arg0 as BaseConfig
        <- rtn as Integer: configName <=> arg0.configName

      default operator

    <?-
      Extended configuration with unique field name 'priority'.
      Does NOT reuse 'configName' which would cause E02020.
    -?>
    ExtendedConfig extends BaseConfig
      priority <- 0

      ExtendedConfig()
        ->
          cn as String
          p as Integer
        super(cn)
        priority :=: p

      override operator <=> as pure
        -> arg0 as ExtendedConfig
        <- rtn as Integer: priority <=> arg0.priority

      default operator

  defines program

    JsonPropertyDemo()
      stdout <- Stdout()

      config <- ExtendedConfig("prod", 10)
      if config?
        stdout.println("Config created: " + $config)

Java: Jackson allows field shadowing (confusing JSON). Python: no compile-time JSON validation. Kotlin: Kotlinx serialization detects some conflicts. Rust: Serde handles field shadowing but can be confusing. Go: encoding/json uses last field wins. EK9: E02020 prevents duplicate JSON property names at compile time.

E02020 JSON ambiguous compile-time duplicate field hierarchy operator property serialization

    ExtendedConfig extends BaseConfig
      configName <- "custom"

Explanation: Parent BaseConfig already has a field named configName. The child cannot reuse that name when both use default operator $$ for JSON. Use a unique field name in the child. See ek9 -h E02020 for details.


Question: Why can't I use type inference inside a generic class body in EK9?

What triggers E06070 TYPE_INFERENCE_NOT_SUPPORTED?

Why does 'inferred <- 2' fail inside a generic class?

Why must all types be explicit in generic bodies?

Answer:
Type inference with '<-' is not allowed inside generic/template class bodies. All types must be explicit because the type parameter T is unknown until instantiation.

See Q646 for type inference limits. See Q58 for generic functions.

defines module qa.generics.no.inference

  defines class

    Container of type T

      default Container()

      default Container()
        -> item as T

      someMethod()
        someVar as Integer: 2
        require someVar?

  defines program

    GenericInferenceDemo()
      stdout <- Stdout()
      greeting <- "hello"
      stdout.println(greeting)

Java: allows var inside generic bodies. Kotlin: allows inference everywhere. Rust: allows inference in generic impls. EK9: forbids all inference in generic bodies for consistency.

E06070 explicit generic inference template type

Explanation: Type inference is not supported inside generic class bodies. Declare all types explicitly. See ek9 -h E06070 for details.


Question: Why does EK9 reject repeated parameter groups across functions?

What triggers E11053 DATA_CLUMP_DETECTED?

Why should I extract repeated parameters into a record?

Answer:
When 3+ functions share 4+ parameters with matching names and types, EK9 detects a data clump (E11053). Extract the parameters into a record.

See Q97 for class vs record. See Q311 for quality checks.

defines module qa.quality.data.clump.record

  defines record

    Address
      street <- String()
      city <- String()
      state <- String()
      zipCode <- String()

      Address()
        ->
          s as String
          c as String
          st as String
          z as String
        street :=: s
        city :=: c
        state :=: st
        zipCode :=: z

      operator <=> as pure
        -> arg0 as Address
        <- rtn as Integer: street <=> arg0.street

      default operator

  defines function

    formatAddress() as pure
      -> addr as Address
      <- rtn as String: `${addr.street}, ${addr.city}`

    validateAddress() as pure
      -> addr as Address
      <- rtn as Boolean: addr.street? and addr.city?

    normalizeAddress()
      -> addr as Address
      <- rtn as Address: Address(s: addr.street, c: addr.city, st: addr.state.upperCase(), z: addr.zipCode)

  defines program

    DataClumpDemo()
      stdout <- Stdout()
      addr <- Address(s: "123 Main", c: "Springfield", st: "IL", z: "62704")
      if validateAddress(addr)
        stdout.println(formatAddress(addr))

Java: no detection, relies on SonarQube. Python: no type-aware detection. Go: favors structs but not enforced. EK9: compile-time error requiring record extraction.

E11053 clump data extract parameter quality record


Question: When should I use a component instead of a class in EK9?

What triggers E11022 CLASS_SHOULD_BE_COMPONENT?

Why does EK9 reject my class with service fields?

What is the difference between class and component in EK9?

Answer:
A class with 4+ service fields (traits/abstract types) and 0 data fields is architecturally a service coordinator — it should be a component, not a class.

COMPONENTS vs CLASSES
- Component: singleton lifecycle, service coordination, DI
- Class: multiple instances, data + behavior

THIS EXAMPLE
ServiceCoordinator uses 4 trait dependencies. It is correctly defined as a component. If it were a class, E11022 would fire.

See Q111 for components. See Q227 for DI.

defines module qa.quality.class.vs.component

  defines trait
    ServiceA
      doA() abstract
    ServiceB
      doB() abstract
    ServiceC
      doC() abstract
    ServiceD
      doD() abstract

  defines class
    ImplA with trait of ServiceA
      override doA()
        require true
    ImplB with trait of ServiceB
      override doB()
        require true
    ImplC with trait of ServiceC
      override doC()
        require true
    ImplD with trait of ServiceD
      override doD()
        require true

  defines component

    ServiceCoordinator
      svcA ServiceA: ImplA()
      svcB ServiceB: ImplB()
      svcC ServiceC: ImplC()
      svcD ServiceD: ImplD()

      orchestrate()
        svcA.doA()
        svcB.doB()
        svcC.doC()
        svcD.doD()

      default operator ?

  defines program

    ComponentDemo()
      stdout <- Stdout()
      stdout.println("Component handles service coordination")

Java: no class/component distinction — Spring @Component is optional. C#: no language-level enforcement. Go: no component construct. EK9: compiler enforces class vs component based on field analysis.

E11022 class component design field quality service trait

Explanation: A class with only service/trait fields and no data fields is a service coordinator. Use 'defines component' instead. See ek9 -h E11022 for details.


Question: Why does stream split require a function or delegate?

What triggers E07860 FUNCTION_OR_DELEGATE_REQUIRED?

Why can't I use split without a predicate in EK9 streams?

What does stream split need as an argument?

Answer:
Stream split requires a predicate function that takes one argument and returns Boolean. Without a predicate, the stream cannot decide how to split elements.

See Q813 for stream rules.

defines module qa.streams.split.needs.function

  defines constant

    SHORT_THRESHOLD <- 2

  defines function

    isShort() as pure
      -> item as String
      <- rtn as Boolean: length item < SHORT_THRESHOLD

  defines program

    StreamSplitDemo()
      collection <- List() of List of String
      cat ["A", "B", "C"] | split by isShort > collection
      require collection?

Java: no built-in split stream op. Python: itertools has no split. EK9: split requires predicate function.

E07860 delegate function pipeline predicate split stream

cat ["A", "B", "C"] | split > collection

Explanation: Stream split requires a predicate function. Without one, the stream cannot decide how to split. See ek9 -h E07860 for details.


Question: How do I avoid dispatcher handler ambiguity with multiple traits?

What triggers E05230 DISPATCHER_HANDLER_AMBIGUITY?

Why is Duck ambiguous when it implements two traits?

How do I resolve dispatcher ambiguity in EK9?

Answer:
When a type implements two traits and handlers exist for both traits at equal cost, the dispatcher cannot choose. Add a specific handler for the ambiguous type.

THIS EXAMPLE
Duck implements Flyable. The processor has a handler for Dog (concrete). Replacing the Dog handler with a Flyable handler would create ambiguity for Duck if Swimmable were also handled.

See Q616 for dispatcher ambiguity. See Q621 for dispatch rules.

defines module qa.dispatcher.no.ambiguity

  defines trait

    Flyable
      fly()
        Stdout().println("Flying")

    Swimmable
      swim()
        Stdout().println("Swimming")

  defines class

    Animal as abstract
      speak() as abstract
      default operator ?

    Dog is Animal
      override speak()
        Stdout().println("Woof")

    Duck is Animal with trait of Flyable, Swimmable
      override speak()
        Stdout().println("Quack")
      override operator ? as pure
        <- rtn as Boolean: true

    AnimalProcessor

      process() as dispatcher
        -> animal as Animal
        animal.speak()

      process()
        -> animal as Dog
        animal.speak()

      default operator ?

  defines program

    DispatcherDemo()
      processor <- AnimalProcessor()
      dog as Animal: Dog()
      if processor? and dog?
        processor.process(dog)

Java: method overloading is compile-time. C#: dynamic dispatch at runtime. Kotlin: sealed when is exhaustive. EK9: compile-time ambiguity detection for all reachable runtime types.

E05230 ambiguity dispatcher handler multiple trait

dispatcher ambiguity
E05230
multiple traits


Question: When should I use 'by' delegation instead of manual method forwarding?

What is E11023 MISSING_BY_DELEGATION in EK9?

Why does EK9 require 'by' delegation for trait forwarding?

How do I eliminate boilerplate delegation code?

Answer:
When a class manually delegates most trait methods to a field, EK9 detects this pattern and requires using the 'by' keyword instead (E11023). The 'by' keyword eliminates boilerplate delegation code.

THE PROBLEM
Manually overriding 5+ trait methods just to forward calls to a field is tedious and error-prone:
  override methodA() -> delegate.methodA()
  override methodB() -> delegate.methodB()
  override methodC() -> delegate.methodC()
This is boilerplate that the compiler can generate automatically.

THE FIX
Use 'with trait of X by field' to auto-delegate all unoverridden methods:
  MyClass with trait of Formatter by delegate
    delegate as Formatter: ConcreteFormatter()
Now only override the methods you need to customize.

BENEFITS
1. Eliminates N lines of forwarding boilerplate
2. New trait methods are automatically delegated
3. Only customized methods need override
4. Clear intent: delegation is visible in the class declaration

See Q210 for trait delegation basics. See Q264 for adapter pattern. See Q266 for cross-cutting concerns via delegation.

defines module qa.quality.use.by.delegation

  defines trait

    <?-
      Formatter trait with multiple methods.
      Used to demonstrate delegation with 'by'.
    -?>
    Formatter
      formatHeading() as abstract
        -> heading as String
        <- rtn as String?

      formatParagraph() as abstract
        -> paragraph as String
        <- rtn as String?

      formatFooter() as abstract
        <- rtn as String?

  defines class

    <?-
      Concrete implementation of Formatter.
      Provides default formatting behavior.
    -?>
    PlainFormatter with trait of Formatter
      override formatHeading()
        -> heading as String
        <- rtn as String: `=== ${heading} ===`

      override formatParagraph()
        -> paragraph as String
        <- rtn as String: "  " + paragraph

      override formatFooter()
        <- rtn as String: "---end---"

      default operator ?

    <?-
      Correct: uses 'by' delegation to auto-delegate Formatter methods.
      Only overrides formatHeading to add custom behavior.
      formatParagraph and formatFooter are auto-delegated.
    -?>
    FancyFormatter with trait of Formatter by delegate
      delegate as Formatter: PlainFormatter()

      FancyFormatter()
        -> formatter as Formatter
        this.delegate: formatter

      override formatHeading()
        -> heading as String
        <- rtn as String: `*** ${heading} ***`

      default operator ?

  defines program

    DelegationDemo()
      stdout <- Stdout()

      plain <- PlainFormatter()
      fancy <- FancyFormatter(plain)

      //formatHeading is overridden in FancyFormatter
      stdout.println(fancy.formatHeading("Title"))

      //formatParagraph is auto-delegated to PlainFormatter
      stdout.println(fancy.formatParagraph("Some content here"))

      //formatFooter is auto-delegated to PlainFormatter
      stdout.println(fancy.formatFooter())

Java: no built-in delegation, manual forwarding or Lombok @Delegate. Kotlin: 'by' delegation on interfaces, same concept. Rust: no delegation, manual impl forwarding. Go: embedded structs provide implicit forwarding. Python: __getattr__ for dynamic delegation. EK9: 'with trait of X by field' with E11023 enforcement when manual delegation detected.

E11023 boilerplate by clean-code composition delegation forwarding override quality trait


Question: Why can't I mix 'by' delegation with many service fields?

What is E11024 HYBRID_CLASS_COMPONENT in EK9?

Why does EK9 flag my class as a hybrid class-component?

How do I separate delegation from service coordination?

Answer:
Using 'by' delegation (class pattern) while having 3+ service fields (component pattern) mixes two architectural roles in one type. The compiler raises E11024 to enforce separation of concerns.

WHY THIS IS A PROBLEM
Delegation classes wrap and decorate a single concern. Components coordinate multiple services. Combining both patterns creates a type that is half-decorator and half-coordinator, making it hard to test, reason about, and maintain.

THE FIX
Split into two types:
1. A focused delegation class that wraps one trait with 'by'
2. A component that coordinates multiple services

THIS EXAMPLE
Shows the correct approach: a delegation class (LoggingReporter) wraps a single trait with 'by' and has at most one or two service fields. The service coordination is kept separate.

See Q856 for class vs component. See Q859 for 'by' delegation. See Q310 for code quality overview.

defines module qa.quality.no.hybrid.class.component

  defines trait

    <?-
      Reporter trait: a single concern for reporting.
    -?>
    Reporter
      report() as abstract
        -> topic as String
        <- rtn as String?

  defines class

    <?-
      Concrete reporter implementation.
    -?>
    PlainReporter with trait of Reporter
      override report()
        -> topic as String
        <- rtn as String: "Report on " + topic

      default operator ?

    <?-
      Correct: focused delegation class.
      Wraps Reporter with 'by' and has minimal service fields.
      No hybrid mixing of delegation and service coordination.
    -?>
    LoggingReporter with trait of Reporter by delegate
      delegate as Reporter: PlainReporter()

      LoggingReporter()
        -> reporter as Reporter
        this.delegate: reporter

      override report()
        -> topic as String
        <- rtn as String: "[LOG] " + delegate.report(topic)

      default operator ?

  defines program

    NoHybridDemo()
      stdout <- Stdout()

      plain <- PlainReporter()
      logging <- LoggingReporter(plain)

      //Delegation class focuses on one concern: adding logging
      stdout.println(logging.report("quarterly-sales"))
      stdout.println(logging.report("annual-review"))

Java: no detection of mixed delegation and service patterns. Spring allows mixing @Delegate with @Autowired freely. Python: no detection. Kotlin: 'by' delegation has no service field checks. Rust: no class/component distinction. EK9: E11024 compile-time enforcement separating delegation from service coordination.

E11024 architecture by class clean-code component delegation hybrid quality separation service

      delegate as Reporter: PlainReporter()
      svcA as Reporter: PlainReporter()
      svcB as Reporter: PlainReporter()
      svcC as Reporter: PlainReporter()
      auditLabel as String: "audit"

      LoggingReporter()

Explanation: Combining 'by' delegation with three or more additional service fields mixes decorator and coordinator roles and triggers E11024 - split into a focused delegation class and a separate component. See ek9 -h E11024 for details.


Question: Why does EK9 reject classes with too many service and data fields?

What triggers E11025 EXCESSIVE_MIXED_RESPONSIBILITIES?

What is the God Class anti-pattern in EK9?

How many service fields can a class have alongside data fields?

Answer:
A class with 3+ service fields AND 3+ data fields is a 'God Class'. Split into a data class (few services) and a service component.

THRESHOLD: >= 3 service fields AND >= 3 data fields.

THIS EXAMPLE
OrderHandler has 2 service fields + 3 data fields = OK (under threshold).

See Q856 for class vs component. See Q311 for quality checks.

defines module qa.quality.avoid.god.class

  defines trait
    ValidatorService
      validate() abstract
    PricingService
      calculatePrice() abstract
    ShippingService
      ship() abstract

  defines class
    ValidatorImpl with trait of ValidatorService
      override validate()
        require true
    PricerImpl with trait of PricingService
      override calculatePrice()
        require true
    ShipperImpl with trait of ShippingService
      override ship()
        require true

  defines class

    OrderHandler
      //2 service fields (under threshold)
      validator ValidatorService: ValidatorImpl()
      pricer PricingService: PricerImpl()
      //3 data fields
      orderId <- "ORD-001"
      customerName <- "Steve"
      totalAmount <- 0

      processOrder()
        validator.validate()
        pricer.calculatePrice()

      default operator ?

  defines program

    GodClassDemo()
      stdout <- Stdout()
      handler <- OrderHandler()
      if handler?
        handler.processOrder()
        stdout.println("Order processed")

Java: detected only by SonarQube. Python: no detection. Go: convention only. EK9: compile-time error preventing God Class.

E11025 class field god mixed quality responsibilities service

      //3 service fields (triggers threshold)
      validator ValidatorService: ValidatorImpl()
      pricer PricingService: PricerImpl()
      shipper ShippingService: ShipperImpl()

Explanation: 3+ service fields AND 3+ data fields triggers E11025. Split into a data class and a service component. See ek9 -h E11025 for details.


Question: Why does EK9 limit injection fields per component?

What is E11040 EXCESSIVE_INJECTION_FIELDS in EK9?

How many injection fields can a component have?

How do I fix too many injected dependencies?

Answer:
Components with more than 4 injection fields (marked with '!') violate the Single Responsibility Principle. The compiler raises E11040 to enforce focused components.

WHY THE LIMIT EXISTS
A component with 5+ injected dependencies is doing too much. Each dependency represents a concern the component must manage. More than 4 suggests the component should be split.

THE FIX
Extract a facade component to group related dependencies:
1. Identify clusters of related injected services
2. Create a facade component that wraps the cluster
3. Inject the facade instead of individual services

THIS EXAMPLE
Shows a component with exactly 3 injection fields, well within the limit. Each dependency is clearly needed for the component's focused responsibility.

See Q227 for compile-time DI validation. See Q229 for circular deps. See Q325 for component patterns.

defines module qa.di.injection.field.limit

  defines component

    <?-
      Abstract service contracts for injection.
    -?>
    Repository as abstract
      findById() as abstract
        -> identifier as String
        <- rtn as String?
      default operator ?

    Notifier as abstract
      notify() as abstract
        -> message as String
      default operator ?

    Auditor as abstract
      record() as abstract
        -> action as String
      default operator ?

    <?-
      Concrete implementations.
    -?>
    InMemoryRepository extends Repository
      override findById()
        -> identifier as String
        <- rtn as String: "item-" + identifier
      default operator ?

    ConsoleNotifier extends Notifier
      override notify()
        -> message as String
        Stdout().println("[NOTIFY] " + message)
      default operator ?

    ConsoleAuditor extends Auditor
      override record()
        -> action as String
        Stdout().println("[AUDIT] " + action)
      default operator ?

    <?-
      Correct: 3 injection fields, within the limit of 4.
      Each dependency is clearly needed for order processing.
    -?>
    OrderProcessor

      repo as Repository!
      notifier as Notifier!
      auditor as Auditor!

      processOrder()
        -> orderId as String
        item <- repo.findById(orderId)
        if item?
          notifier.notify(`Processing ${item}`)
          auditor.record(`Processed order ${orderId}`)

      default operator ?

  defines application

    OrderApp
      register InMemoryRepository() as Repository
      register ConsoleNotifier() as Notifier
      register ConsoleAuditor() as Auditor

  defines program

    InjectionLimitDemo()
      stdout <- Stdout()
      stdout.println("OrderProcessor has 3 injection fields (within limit of 4)")
      stdout.println("Components with 5+ injection fields trigger E11040")

Java: Spring has no limit on @Autowired fields (only advisory from SonarQube). Python: no limit. Kotlin: no limit. Go: no DI framework limits. Rust: no DI concept. EK9: E11040 compile-time limit of 4 injection fields per component.

E11040 SRP clean-code component dependency facade field inject injection limit quality

      repo as Repository!
      notifier as Notifier!
      auditor as Auditor!
      extra1 as Repository!
      extra2 as Notifier!

Explanation: 5 injection fields exceeds the limit of 4. Extract related services into a facade component and inject the facade instead. See ek9 -h E11040 for details.


Question: Why must module constants be in a single file?

What is E11066 CONSTANTS_IN_MULTIPLE_FILES in EK9?

How do I consolidate scattered constants?

Why does EK9 require constants in one file per module?

Answer:
When constants for a module are scattered across 3+ source files, EK9 requires consolidation into a single file (E11066). This is a module-level check for discoverability.

WHY CONSOLIDATION MATTERS
Constants scattered across files are hard to find, easy to duplicate, and impossible to review as a group. Consolidating them into one file per module provides:
1. A single reference point for all module constants
2. Easy duplicate detection during code review
3. Clear organization by concern using doc comments
4. Simplified maintenance when values change

THE FIX
Move all 'defines constant' blocks for a module into one file. Organize with doc comments:
  defines constant
    //Temperature thresholds
    FREEZING_POINT <- 0.0
    BOILING_POINT <- 100.0
    //Retry configuration
    MAX_RETRIES <- 3
    RETRY_DELAY_MS <- 500

THIS EXAMPLE
Shows all module constants properly consolidated in a single file with clear organization.

See Q695 for named constants. See Q800 for magic literal detection. See Q310 for code quality overview.

defines module qa.quality.consolidate.constants

  defines constant

    <?-
      Temperature thresholds.
      All temperature-related constants grouped together.
    -?>
    FREEZING_CELSIUS <- 0.0
    BOILING_CELSIUS <- 100.0
    BODY_TEMP_CELSIUS <- 37.0

    <?-
      Retry configuration constants.
      Used by network and service components.
    -?>
    MAX_RETRIES <- 3
    RETRY_DELAY_MS <- 500
    CONNECTION_TIMEOUT_MS <- 5000

    <?-
      Formatting constants.
      Used by output and report functions.
    -?>
    SEPARATOR_LINE <- "----------------------------------------"
    INDENT_SPACES <- "    "

  defines function

    <?-
      Classify temperature using consolidated constants.
      All thresholds come from one constants block.
    -?>
    classifyTemperature() as pure
      -> celsius as Float
      <- classification as String: "warm"

      if celsius <= FREEZING_CELSIUS
        classification: "freezing"
      else if celsius >= BOILING_CELSIUS
        classification: "boiling"

    <?-
      Format a report line using the shared formatting constants.
    -?>
    formatReportLine() as pure
      -> content as String
      <- rtn as String: INDENT_SPACES + content

  defines program

    ConsolidatedConstantsDemo()
      stdout <- Stdout()

      stdout.println(SEPARATOR_LINE)
      stdout.println(formatReportLine("Temperature Classifications"))
      stdout.println(SEPARATOR_LINE)

      stdout.println(formatReportLine(`Ice water: ${classifyTemperature(-5.0)}`))
      stdout.println(formatReportLine(`Room temp: ${classifyTemperature(22.0)}`))
      stdout.println(formatReportLine(`Steam: ${classifyTemperature(105.0)}`))

      stdout.println(SEPARATOR_LINE)
      stdout.println(formatReportLine(`Max retries: ${MAX_RETRIES}`))
      stdout.println(formatReportLine(`Timeout: ${CONNECTION_TIMEOUT_MS}ms`))

Java: no enforcement of constant file organization. Python: convention to use constants.py but not enforced. Kotlin: no enforcement. Rust: no enforcement. Go: convention to use const blocks but scattered is allowed. EK9: E11066 compile-time enforcement requiring module constants in a single file.

E11066 clean-code consolidate constant discoverability file module organization quality scattered


Question: Why must the negate operator ~ return the same type as its class?

What triggers E07410 MUST_RETURN_SAME_AS_CONSTRUCT_TYPE?

Why does my negate operator fail with wrong return type?

How do I correctly implement the ~ negate operator in EK9?

Answer:
The negate operator ~ must return the SAME type as the enclosing class. Returning a different type is a semantic error (E07410).

WHAT NEGATE DOES
Negate produces the logical or arithmetic inverse of the current object:
  Inverter -> negated Inverter
  Polarity -> opposite Polarity
  Toggle -> flipped Toggle

CORRECT PATTERN
  operator ~ as pure
    <- rtn as Inverter: Inverter()
The return type (Inverter) matches the enclosing class (Inverter).

INCORRECT PATTERN
  operator ~ as pure
    <- rtn as Float: 1.0
Returning Float from an Inverter class triggers E07410 because Float is not Inverter.

USAGE
  original <- Inverter(true)
  negated <- ~original  // negated is an Inverter

See Q238 for operator overview. See Q839 for promote operator (which must return a DIFFERENT type).

defines module qa.operators.negate.same.type

  defines class

    <?-
      Inverter with negate operator returning the same type.
      This is the correct pattern for negation.
    -?>
    Inverter
      active <- true

      Inverter() as pure
        -> initialState as Boolean
        active :=: initialState

      operator ~ as pure
        <- rtn as Inverter: Inverter(active)

      operator $ as pure
        <- rtn as String: `active: ${active}`

      default operator ?

  defines program

    NegateDemo()
      stdout <- Stdout()
      original <- Inverter(true)
      negated <- ~original
      stdout.println($negated)

Java: No negate operator for custom types; bitwise ~ returns int/long. Python: __invert__ can return any type (no enforcement). Rust: Not trait requires Output=Self by convention but not enforced by compiler. Kotlin: operator fun not() can return any type. EK9: operator ~ enforces return type matches enclosing class at compile time.

E07410 construct negate operator return same type ~

      operator ~ as pure
        <- rtn as Float: 1.0

Explanation: The negate operator ~ must return the same type as the enclosing class. Returning Float from an Inverter class is not valid negation. Return an Inverter instead. See ek9 -h E07410 for details.


Question: Why does EK9 flag checking empty on a freshly constructed list?

What triggers E08092 REDUNDANT_EMPTY_CHECK?

Why is checking empty right after creating a list redundant?

How does EK9 detect tautological empty checks?

Answer:
EK9 uses data flow analysis to detect redundant empty checks. A freshly created collection is always empty, so checking 'if items empty' immediately after creation is a tautology — the condition is always true.

REDUNDANT (E08092)
  items <- List() of String
  if items empty           // ALWAYS true — nothing was added
    result: "nothing here"

VALID CHECK
  items <- List() of String
  items += "hello"
  if items empty           // valid — state changed since creation
    result: "nothing here"

Adding items between creation and the empty check makes the check meaningful because the collection state is no longer provably empty.

See Q820 for redundant empty check overview. See Q310 for code quality.

defines module qa.quality.redundant.empty

  defines function

    checkEmptiness()
      -> greeting as String
      <- result as String: String()

      items <- List() of String
      items += greeting
      if items empty
        result: "nothing here"
      else
        result: "has content"

  defines program

    RedundantEmptyDemo()
      stdout <- Stdout()

      outcome <- checkEmptiness("hello")
      stdout.println(`Result: ${outcome}`)

Java: no detection — isEmpty() on new ArrayList compiles silently. Python: no detection. Rust: no detection. Go: no detection. EK9: compile-time error for provably redundant empty checks via data flow analysis.

E08092 collection data empty flow list redundant tautology

      items += greeting
      if items empty

Explanation: Without adding any items, the list is provably empty. Checking 'if items empty' is always true — the compiler detects this tautology. Add items before checking. See ek9 -h E08092 for details.


Question: Why must functions used with stream call return a value?

What triggers E07490 FUNCTION_MUST_RETURN_VALUE in streams?

Why can't I use a void function with cat and call?

What happens when a function in a stream pipeline returns nothing?

Answer:
Functions used with call in a stream pipeline must return a value. The return value becomes the next element flowing downstream. A void function produces nothing, breaking the pipeline.

CORRECT PATTERN
  getSteve()
    <- rtn <- "Steve"
  cat [getSteve] | call > collector
The function returns a String, which flows into the collector.

INCORRECT PATTERN
  doesNotReturn()
    require true
  cat [doesNotReturn] | call > collector
The void function produces nothing — the pipeline has no elements to collect.

See Q843 for function return requirement. See Q813 for call/async rules.

defines module qa.streams.call.void.function

  defines function

    getSteve()
      <- rtn <- "Steve"

    doesNotReturn()
      require true

  defines class
    StringCollector
      received <- String()
      operator |
        -> item as String
        if item?
          received: String(item)
      override operator ? as pure
        <- rtn as Boolean: received?

  defines function

    StreamCallDemo()
      collector <- StringCollector()
      cat [getSteve] | call > collector
      require collector?

Java: Supplier returns T, Runnable returns void — Stream.generate requires Supplier. Python: map expects return values. EK9: call requires supplier-style functions that return a value.

E07490 call function pipeline return stream supplier void

Explanation: Functions used with stream call must return a value. The void function doesNotReturn produces nothing for the pipeline. Use a function that returns a value. See ek9 -h E07490 for details.


Question: Why must functions used with stream call take zero arguments?

What triggers E06310 REQUIRE_NO_ARGUMENTS in streams?

Why can't I stream a function that takes parameters through call?

What is the correct function shape for stream call?

Answer:
Functions used with call in a stream pipeline must take ZERO arguments. The stream invokes them without parameters — they act as suppliers.

CORRECT PATTERN
  getGreeting()
    <- rtn <- "Hello EK9"
  cat [getGreeting] | call > collector
Zero-argument function that returns a value.

INCORRECT PATTERN
  needsArg()
    -> prefix as String
    <- rtn <- "Hello EK9"
  cat [needsArg] | call > collector
The function takes a parameter — the stream has no way to supply it.

See Q844 for call argument rules. See Q843 for return requirement.

defines module qa.streams.call.zero.args

  defines function

    getGreeting()
      <- rtn <- "Hello EK9"

    needsArg()
      -> prefix as String
      <- rtn as String: prefix

  defines class
    StringCollector
      received <- String()
      operator |
        -> item as String
        if item?
          received: String(item)
      override operator ? as pure
        <- rtn as Boolean: received?

  defines function

    StreamZeroArgsDemo()
      collector <- StringCollector()
      cat [getGreeting] | call > collector
      require collector?

Java: Supplier has get() with no arguments. Python: zero-arg callables used with map/filter. EK9: call requires zero-argument supplier functions.

E06310 arguments call function pipeline stream supplier zero

Explanation: Functions used with stream call must take no arguments. The function needsArg requires a parameter the stream cannot supply. Use a zero-argument function. See ek9 -h E06310 for details.


Question: Why can't I use HTTPRequest as a path parameter type in EK9 services?

What triggers E07790 SERVICE_INCOMPATIBLE_PARAM_TYPE_NON_REQUEST?

When is HTTPRequest invalid as a service parameter type?

How do I correctly bind service path parameters?

Answer:
HTTPRequest can only be used with :=: REQUEST binding. Using HTTPRequest as a PATH parameter type triggers E07790 because path parameters are parsed from URI segments — they must be simple types like Integer or String.

CORRECT PATTERN
  findById() as GET for :/{userId}
    -> userId as Integer
Integer is a valid path parameter type.

INCORRECT PATTERN
  findById() as GET for :/{userId}
    -> userId as HTTPRequest
HTTPRequest cannot be bound to a PATH segment. Use :=: REQUEST binding if you need the full request.

VALID PATH PARAMETER TYPES
Integer, String, Date, Duration, DateTime, Time, Millisecond.

See Q846 for parameter type rules. See Q202 for parameter binding.

defines module qa.webdeep.service.request.param.type

  defines constant

    JSON_RESPONSE <- "application/json"

  defines service

    <?-
      Service with valid Integer path parameter.
      Path parameters must be simple parseable types.
    -?>
    AccountService :/accounts open

      findById() as GET for :/{userId}
        -> userId as Integer
        <- response as HTTPResponse: (capturedId: userId) with trait HTTPResponse
          override content()
            <- rtn as String: `{"userId": ${capturedId}}`
          override status() as pure
            <- rtn as Integer: 200
          override contentType() as pure
            <- rtn as String: JSON_RESPONSE
          override cacheControl() as pure
            <- rtn as String: "no-cache"
          override contentLanguage() as pure
            <- rtn as String: "en"
          default operator ?

  defines application

    AccountApp
      register AccountService()

  defines program

    ServiceParamTypeDemo()
      stdout <- Stdout()
      stdout.println("Valid path param types: Integer, String, Date, Time")
      stdout.println("Invalid: HTTPRequest (use :=: REQUEST binding instead)")

Java Spring: @PathVariable binds to any type with a converter. C# ASP.NET: model binding to complex types. Go: manual string parsing. Python Flask: parameter converters at runtime. EK9: compile-time restriction prevents HTTPRequest from being used as a path or query parameter.

E07790 HTTPRequest Integer binding parameter path service type

Explanation: HTTPRequest cannot be used as a path parameter type. Path parameters are parsed from URI segments and must be simple types like Integer or String. Use :=: REQUEST binding for HTTPRequest. See ek9 -h E07790 for details.


Question: Why must all EK9 service methods declare a return value?

What triggers E07800 SERVICE_MISSING_RETURN?

Why can't my service method omit the return declaration?

What return type do EK9 service methods require?

Answer:
ALL EK9 service methods must have a return declaration. Services are HTTP endpoints and must return an HTTPResponse to express status codes, headers, and content. A method without a return declaration triggers E07800.

CORRECT PATTERN
  healthCheck() as GET for :/status
    <- response as HTTPResponse: () with trait HTTPResponse
      ...
The method declares a return of HTTPResponse.

INCORRECT PATTERN
  healthCheck() as GET for :/status
    require true
No return declaration — the compiler cannot determine what HTTP response to send.

See Q845 for service return type. See Q659 for service return patterns.

defines module qa.webdeep.service.needs.return

  defines service

    <?-
      Service with proper return declaration.
      All service methods must return HTTPResponse.
    -?>
    StatusService :/api open

      healthCheck() as GET for :/status
        <- response as HTTPResponse: () with trait HTTPResponse
          override content()
            <- rtn as String: `{"status": "healthy"}`
          override status() as pure
            <- rtn as Integer: 200
          override contentType() as pure
            <- rtn as String: "application/json"
          override cacheControl() as pure
            <- rtn as String: "no-cache"
          override contentLanguage() as pure
            <- rtn as String: "en"
          default operator ?

  defines application

    StatusApp
      register StatusService()

  defines program

    ServiceReturnDemo()
      stdout <- Stdout()
      stdout.println("All service methods must declare a return value")
      stdout.println("The return type must be compatible with HTTPResponse")

Java Spring: void controllers write to response directly. C# ASP.NET: void actions with Response.Write. Go: handlers write to ResponseWriter without return. Python Flask: can return None (500 error). EK9: mandatory HTTPResponse return ensures every endpoint has a well-defined response.

E07800 HTTPResponse endpoint method missing return service

      healthCheck() as GET for :/status
        require true

Explanation: Service methods must always return an HTTPResponse. Omitting the return declaration means the compiler cannot determine the HTTP response. See ek9 -h E07800 for details.


Question: How does adding a concrete type handler resolve dispatcher ambiguity?

What triggers E05230 DISPATCHER_HANDLER_AMBIGUITY?

How do I fix dispatcher ambiguity for types implementing multiple traits?

Why does replacing a concrete handler with a trait handler cause ambiguity?

Answer:
When a class implements two traits and a dispatcher has handlers for both traits, dispatching that class is ambiguous (E05230) because both handlers match at equal cost (0.10 each). Adding a handler for the concrete type resolves the ambiguity because exact match costs 0.00.

THE PROBLEM
Duck implements Flyable and Swimmable. Handlers exist for both traits at cost 0.10 each. Dispatching Duck is ambiguous.

THE SOLUTION
Add a handler specifically for Duck (cost 0.00 — exact match). This always wins over trait handlers.

CORRECT PATTERN
  process()
    -> animal as Duck
    <- rtn as String: animal.speak()
Exact match handler at cost 0.00 beats trait handlers at cost 0.10.

INCORRECT PATTERN (removes Duck handler)
Without the Duck handler, Duck matches both Flyable (0.10) and Swimmable (0.10) at equal cost. Ambiguity.

See Q616 for ambiguity basics. See Q617 for diamond trait dispatch.

defines module qa.dispatchervalidation.ambiguity.resolution

  defines trait

    Flyable
      fly() as abstract
        <- rtn as String?

    Swimmable
      swim() as abstract
        <- rtn as String?

  defines class

    Animal as abstract
      speak() as abstract
        <- rtn as String?
      default operator ?

    Dog extends Animal
      override speak()
        <- rtn as String: "woof"

    Duck extends Animal with trait of Flyable, Swimmable
      override speak()
        <- rtn as String: "quack"
      override fly()
        <- rtn as String: "flapping"
      override swim()
        <- rtn as String: "paddling"
      override operator ? as pure
        <- rtn as Boolean: true

    <?-
      Dispatcher with handlers for Animal (base), Flyable, Swimmable,
      and Duck (concrete). The Duck handler resolves ambiguity.
    -?>
    AnimalProcessor
      process() as dispatcher
        -> animal as Animal
        <- rtn as String: animal.speak()

      process()
        -> animal as Dog
        <- rtn as String: animal.speak()

      process()
        -> creature as Flyable
        <- rtn as String: creature.fly()

      process()
        -> creature as Swimmable
        <- rtn as String: creature.swim()

      //Duck handler resolves ambiguity (cost 0.00 beats trait cost 0.10)
      process()
        -> animal as Duck
        <- rtn as String: animal.speak()

  defines function

    testAmbiguityResolution()
      processor <- AnimalProcessor()
      dog <- Dog()
      duck <- Duck()
      require processor.process(dog) == "woof"
      require processor.process(duck) == "quack"

Java: method overloading resolved at compile time, no runtime dispatch ambiguity. C++: multiple inheritance ambiguity resolved with virtual base classes. Python: C3 linearization provides deterministic ordering. Kotlin: compiler error for interface default method conflicts. EK9: E05230 detects dispatch ambiguity at compile time, requires structural resolution.

E05230 ambiguity concrete cost dispatcher duck handler resolution trait

//Duck handler removed — ambiguity not resolved

Explanation: Without the Duck-specific handler, Duck matches both Flyable and Swimmable at equal cost (0.10 each). The dispatcher cannot choose. Add a concrete type handler to resolve. See ek9 -h E05230 for details.


Question: How do I print a message to the console in EK9?

What is the EK9 equivalent of System.out.println?

Answer:
In Java you write System.out.println(), in Python you write print(). In EK9 the equivalent is:

  stdout <- Stdout()
  stdout.println("your message")

The '<-' creates a local variable called stdout that holds a reference to standard output. Then you call println() on it. This two-step pattern — create the output stream, then write to it — appears in every EK9 program.

You must wrap this inside 'defines module' and 'defines program' blocks. See Q1 for the full structure. Use 'ek9 -h Stdout' for all available output methods.

defines module qa.getting.started.hello.variant

  defines program

    PrintMessage()
      stdout <- Stdout()
      stdout.println("Welcome to EK9")
      stdout.println("Programming is fun")

Java: System.out.println(). Python: print(). Go: fmt.Println(). EK9: Stdout().println().

console message output print println stdout text


Question: How do I declare variables and use string interpolation in an EK9 program?

Show me variable declaration with interpolated strings in EK9

Answer:
Declare variables with '<-' (type is inferred). Use backtick strings with ${expression} for interpolation. EK9 infers the type from the assigned value — no need to declare types explicitly for locals.

See Q37 for strings. See Q22 for variable declaration. Use 'ek9 -h String' for string methods.

defines module qa.getting.started.variables

  defines program

    VariableDemo()
      stdout <- Stdout()

      greeting <- "Hello"
      userName <- "Steve"
      age <- 42

      stdout.println(`${greeting}, ${userName}!`)
      stdout.println(`You are ${age} years old`)

Java: var keyword (Java 10+). Python: dynamic typing. Kotlin: val/var. EK9: '<-' with type inference.

backtick declaration inference interpolation string template variable

variable declaration
string interpolation
type inference

Oracle can generate a program construct with variable declarations and string interpolation.


Question: How do I write a pure function in EK9 that takes parameters and returns a result?

Show me a function with input and output in EK9

EK9 function with parameters and return value

Answer:
Functions use '->' for input parameters and '<-' for the return value. Mark functions 'as pure' when they have no side effects — pure functions only compute from their inputs.

The return variable is declared on the '<-' line and automatically returned. EK9 has no 'return' statement — the compiler ensures all paths initialise the return variable.

See Q49 for function basics. See Q560 for purity contracts. Use 'ek9 -h function' for syntax.

defines module qa.functions.pure.basics

  defines constant

    ADULT_AGE <- 18

  defines function

    calculateArea() as pure
      ->
        width as Float
        height as Float
      <-
        rtn as Float: width * height

    isAdult() as pure
      -> age as Integer
      <- rtn as Boolean: age >= ADULT_AGE

    formatGreeting() as pure
      -> personName as String
      <- rtn as String: `Hello, ${personName}!`

  defines program

    FunctionDemo()
      stdout <- Stdout()

      area <- calculateArea(5.0, 3.0)
      stdout.println(`Area: ${area}`)

      stdout.println(`Adult: ${isAdult(21)}`)
      stdout.println(formatGreeting("Steve"))

Java: methods with return type. Python: def with return. Rust: fn with ->. EK9: '<-' declares return, 'as pure' enforces no side effects.

function input output parameter pure return side-effect

Oracle can generate a pure function with parameters and return value.


Question: How do I create a class with a constructor and methods in EK9?

Show me a basic EK9 class with state and behaviour

How do I define a class with fields and methods?

Answer:
Classes have private fields (initialised with '<-'), constructors, and methods. Fields are always private in classes. Use ':=:' (copy) to assign constructor parameters to fields. Add 'default operator ?' at the end for the isSet check.

See Q93 for class basics. See Q94 for constructors. See Q96 for operators. Use 'ek9 -h class' for syntax.

defines module qa.classes.with.methods

  defines class

    BankAccount
      ownerName <- String()
      balance <- 0.0

      BankAccount()
        ->
          owner as String
          initialBalance as Float
        ownerName :=: owner
        balance :=: initialBalance

      deposit()
        -> amount as Float
        balance += amount

      getBalance()
        <- rtn as Float: Float(balance)

      describe()
        <- rtn as String: `${ownerName}: balance ${balance}`

      default operator ?

  defines program

    BankDemo()
      stdout <- Stdout()

      account <- BankAccount("Steve", 100.0)
      account.deposit(50.0)

      if account?
        stdout.println(account.describe())
        stdout.println(`Balance: ${account.getBalance()}`)

Java: public/private fields. Python: self.field. Kotlin: data class. EK9: fields always private, '<-' initialises, ':=:' copies.

behaviour class constructor field method private state

Oracle can generate a class with constructor, methods, and operator declarations.