Question: What are the access modifier rules for method overrides?

What is E05130 method access modifiers differ?

Can I change the visibility of an overridden method?

Can I make an override more or less restrictive?

Answer:
Note: override applies to both methods and operators (e.g., override operator ? as pure, override operator $ as pure).

When overriding a method, the access modifier must be at least as permissive as the parent. You cannot make an override more restrictive. The compiler reports E05130 for violations.

THE RULE
Public parent method requires public override (same level). Protected parent method allows protected or public override (same or wider). Private methods cannot be overridden (not visible to children).

THE ERROR: E05130
E05130 fires when an override is more restrictive than the parent. For example, making a public parent method protected or private in the child.

WHY THIS RULE
Liskov Substitution Principle: if code calls parent.method(), it expects child.method() to be equally accessible. Reducing access would break polymorphic code.

DEFAULT ACCESS
In EK9, methods without an explicit modifier are public. Use 'private' or 'protected' to restrict access.

NO PRIVATE OVERRIDE
Private methods are not inherited and cannot be overridden. They are invisible to child classes.

See Q570 for override basics. See Q572 for false override claims. See Q95 for field visibility.

defines module qa.override.accessmodifiers

  defines constant

    MIN_ENHANCED_LENGTH <- 2

  defines class

    Service as open
      //Public method (default)
      process() as pure
        -> request as String
        <- rtn as String: "processed: " + request

      //Protected method
      protected validate() as pure
        -> input as String
        <- rtn as Boolean: length input > 0

      default operator ?

    //Correct: public override of public method
    EnhancedService extends Service
      override process() as pure
        -> request as String
        <- rtn as String: "enhanced: " + request

      //Correct: can widen protected to public
      //Or keep it protected (both are valid)
      override protected validate() as pure
        -> input as String
        <- rtn as Boolean: length input > MIN_ENHANCED_LENGTH

      default operator ?

  defines program

    AccessModifierRulesDemo()
      stdout <- Stdout()

      svc <- EnhancedService()
      stdout.println(svc.process("hello"))

Java: same rule, cannot reduce visibility in override. Kotlin: same rule, override cannot be more restrictive. C#: same rule for virtual methods. EK9: E05130 enforces access modifier consistency in overrides.

E05130 abstract access function inherit modifier open override private protected public restrictive virtual visibility

Explanation: Making an override more restrictive than the parent is forbidden. The parent process() is public, so a private override would violate the Liskov Substitution Principle. See ek9 -h E07010 for details.

Explanation: Narrowing a protected parent method to private in the child violates access modifier rules. The override must be at least as permissive as the parent. See ek9 -h E07010 for details.


Question: What happens if I try to extend or override in a closed type?

What is E05100 override inappropriate for closed types?

Can I override methods if the parent is not 'as open'?

Answer:
EK9 types are closed by default. You can only extend a class that is declared 'as open' or 'as abstract'. Attempting to extend a closed class produces E05030. Since you cannot extend a closed class, you cannot override its methods.

CLOSED BY DEFAULT
Every class without 'as open' or 'as abstract' is closed:
  FinalProcessor
    process() ...
No class can extend FinalProcessor.

OPEN FOR EXTENSION
Add 'as open' to allow extension:
  ProcessorBase as open
    process() ...
Now children can extend and override.

ABSTRACT IS ALWAYS OPEN
Abstract classes must be extended (they are incomplete), so they are always open:
  AbstractProcessor as abstract
    process() as abstract ...

WHY CLOSED BY DEFAULT
Prevents fragile base class problems. Reduces the surface area for bugs. Forces deliberate design for extension. Follows modern language trends (Kotlin, Swift).

See Q101 for why types are closed by default. See Q102 for 'as open'. See Q103 for abstract classes. See Q570 for override basics.

defines module qa.override.closedtype

  defines constant

    MIN_STRICT_LENGTH <- 3

  defines class

    //Closed class: cannot be extended
    ClosedValidator
      validate() as pure
        -> input as String
        <- rtn as Boolean: length input > 0

      default operator ?

    //Open class: can be extended and methods overridden
    OpenValidator as open
      validate() as pure
        -> input as String
        <- rtn as Boolean: length input > 0

      default operator ?

    //Extending the open class is allowed
    StrictValidator extends OpenValidator
      override validate() as pure
        -> input as String
        <- rtn as Boolean: length input > MIN_STRICT_LENGTH

      default operator ?

    //Abstract class: always open
    AbstractValidator as abstract
      check() as pure abstract
        -> input as String
        <- rtn as Boolean?

      default operator ?

    //Must extend abstract to use it
    EmailValidator extends AbstractValidator
      override check() as pure
        -> input as String
        <- rtn as Boolean: input contains "@"

      default operator ?

  defines program

    ClosedTypeDemo()
      stdout <- Stdout()

      //Closed class used directly
      closed <- ClosedValidator()
      stdout.println(`Closed: ${ closed.validate("hi")}`)

      //Open class hierarchy
      strict <- StrictValidator()
      stdout.println(`Strict: ${strict.validate("hi")}`)
      stdout.println(`Strict: ${strict.validate("hello")}`)

      //Abstract class hierarchy
      emailCheck <- EmailValidator()
      stdout.println(`Email: ${emailCheck.check("user@host")}`)
      stdout.println(`Email: ${emailCheck.check("invalid")}`)

Java: all classes open by default, 'final' to close. Python: all classes open. Kotlin: classes closed by default, 'open' to allow extension. Swift: classes closed by default, 'open' to allow overriding. EK9: closed by default, 'as open' to allow extension.

E05030 abstract closed default extend final inherit migrate open override virtual

Explanation: ClosedValidator is not declared as open, so no class can extend it. EK9 types are closed by default. See ek9 -h E05030 for details.

Explanation: When overriding the validate method from OpenValidator, the override keyword is mandatory. Omitting it causes a shadowing error. See ek9 -h E05120 for details.


Question: How do overrides work in deep class hierarchies?

Does override apply to grandparent methods?

How does a three-level override chain work?

Must each level use 'override' in a deep hierarchy?

Answer:
In a deep hierarchy (grandparent, parent, child), each level that replaces a method must use 'override'. The keyword is required at every level that provides a new implementation.

OVERRIDE WORKS ON BOTH METHODS AND OPERATORS
The override keyword applies to methods AND operators:
  override describe() as pure      method override
  override operator ? as pure      operator override
Both follow the same rule: if the parent defines it, you must say override.

THREE-LEVEL PATTERN
Grandparent declares the method. Parent overrides it (must use 'override'). Grandchild overrides again (must use 'override'). Each level independently declares its intent to replace.

EVERY LEVEL NEEDS OVERRIDE
Even though grandparent is the original, and parent already overrides, the grandchild must ALSO say 'override'. There is no implicit inheritance of the override status. This applies equally to methods and operators.

SUPER ACCESS
Each level can access the immediate parent with 'super':
  override describe()
    parentDesc <- super.describe()
    <- rtn as String: parentDesc + " + child"

SKIPPING LEVELS
If the parent does NOT override (keeps grandparent behavior), the grandchild can still override the grandparent method. The override applies to whatever implementation was last provided.

See Q570 for override basics. See Q567 for purity through chains. See Q102 for 'as open'.

defines module qa.override.deepchain

  defines class

    //Level 1: grandparent — operator ? needs override (inherited from base)
    Transport as open
      describe() as pure
        <- rtn as String: "transport"

      capacity() as pure
        <- rtn as Integer: 0

      //override on operator — same keyword as methods
      override operator ? as pure
        <- rtn as Boolean: true

      operator $ as pure
        <- rtn as String: `Transport: ${describe()}`

    //Level 2: parent overrides methods AND operators
    LandTransport extends Transport as open
      override describe() as pure
        <- rtn as String: "land transport"

      override capacity() as pure
        <- rtn as Integer: 4

      //override on operator $ — parent defined it, so override required
      override operator $ as pure
        <- rtn as String: `Land: ${describe()}`

    //Level 3: grandchild overrides again — methods and operators
    Truck extends LandTransport
      override describe() as pure
        <- rtn as String: "truck"

      override capacity() as pure
        <- rtn as Integer: 20

      override operator $ as pure
        <- rtn as String: `Truck: ${describe()}`

    //Another branch at level 3
    Motorcycle extends LandTransport
      override describe() as pure
        <- rtn as String: "motorcycle"

      override capacity() as pure
        <- rtn as Integer: 2

      override operator $ as pure
        <- rtn as String: `Bike: ${describe()}`

  defines program

    DeepOverrideChainDemo()
      stdout <- Stdout()

      //Each level has its own implementation
      items <- List() of Transport
      items += Transport()
      items += LandTransport()
      items += Truck()
      items += Motorcycle()

      for item in items
        stdout.println(`${item.describe()}: capacity ${item.capacity()}`)

Java: @Override at each level is recommended but optional. Kotlin: override at each level is mandatory. C#: override at each level is required. EK9: override is mandatory at every level in the chain.

abstract chain child class deep grandparent hierarchy inherit level open override parent virtual

Explanation: At every level of the hierarchy, the override keyword is required when replacing a parent method. Omitting it at any level triggers shadowing detection. See ek9 -h E05120 for details.

Explanation: If LandTransport extended Truck which extends LandTransport, a circular hierarchy would be created. The compiler detects cycles at any depth. See ek9 -h E05030 for details.


Question: How do overrides work when a class implements a trait and extends a parent?

What happens when a method comes from both a parent class and a trait?

How does EK9 resolve overrides from class and trait sources?

Can I override methods from both parent and trait?

Answer:
A class can extend a parent AND implement traits. When the same method appears in both, the class must provide an override that satisfies both contracts.

BOTH SOURCES
If a parent class has method X and a trait also declares method X with the same signature, the child class must override it once. The single override satisfies both.

TRAIT-ONLY METHODS
Methods that exist only in the trait (not in the parent) are overridden with 'override' just like any other inherited method.

PARENT-ONLY METHODS
Methods that exist only in the parent are overridden with 'override' in the normal way.

PURITY FROM EITHER SOURCE
If either the parent method or the trait method is pure, the override must be pure. The strictest contract wins.

See Q106 for trait basics. See Q107 for multiple traits. See Q570 for override basics. See Q578 for open, abstract, and override relationships.

defines module qa.override.classandtrait

  defines trait

    Printable
      display() as pure abstract
        <- rtn as String?

    Sizeable
      size() as pure abstract
        <- rtn as Integer?

  defines class

    Container as open
      describe() as pure
        <- rtn as String: "container"

      default operator ?

    //Extends parent AND implements traits
    NamedContainer extends Container with trait of Printable, Sizeable
      containerName <- String()
      itemCount <- 0

      NamedContainer()
        ->
          containerName as String
          itemCount as Integer
        this.containerName: containerName
        this.itemCount: itemCount

      //Override from parent class
      override describe() as pure
        <- rtn as String: "named container: " + containerName

      //Override from Printable trait
      override display() as pure
        <- rtn as String: `${containerName} (${itemCount} items)`

      //Override from Sizeable trait
      override size() as pure
        <- rtn as Integer: itemCount

      default operator ?

  defines program

    ClassAndTraitOverrideDemo()
      stdout <- Stdout()

      nc <- NamedContainer("toolbox", 15)

      //Using through parent type
      container <- nc
      stdout.println(container.describe())

      //Using through trait types
      printable <- nc
      stdout.println(printable.display())

      sizeable <- nc
      stdout.println(`Size: ${sizeable.size()}`)

Java: class extends + interface implements, @Override for both. Kotlin: class extends + interface implements, override required. EK9: class extends + 'with trait of', override required for both sources.

abstract both class contract implement inherit open override satisfy trait virtual

Explanation: When implementing a trait method, the override keyword is required. Omitting it on display from the Printable trait triggers shadowing detection. See ek9 -h E05120 for details.

Explanation: Claiming override on a method name that does not exist in the parent class or any implemented trait is a false override claim. See ek9 -h E05110 for details.

Oracle can generate override method stubs when a class extends a parent and implements a trait.


Question: How do I override operators in EK9?

How do I override operator ? in a child class?

Must I use 'override' for operators too?

Answer:
Operators follow the same override rules as methods. When a parent class defines an operator, the child must use 'override operator' to replace it.

OVERRIDE OPERATOR ? (ISSET)
The most commonly overridden operator is '?'. Since all types inherit operator ? from the base, custom classes use 'override operator ?':
  override operator ? as pure
    <- rtn as Boolean: name?

OVERRIDE COMPARISON
If a parent defines operator <=>, the child uses 'override operator <=>':
  override operator <=> as pure
    -> other as MyType
    <- rtn as Integer: ...

OVERRIDE STRING
If a parent defines operator $, the child overrides it:
  override operator $ as pure
    <- rtn as String: ...

DEFAULT OPERATOR
The 'default operator ?' shorthand can be used in any class. When a parent already has operator ?, using 'default operator ?' in the child effectively overrides it with the default implementation.

See Q570 for override basics. See Q245 for custom type operators. See Q568 for pure operators. See Q96 for class operators.

defines module qa.override.operator

  defines class

    Measurement as open
      amount <- 0.0

      Measurement()
        -> amount as Float
        this.amount: amount

      amount() as pure
        <- rtn as Float: amount

      operator <=> as pure
        -> other as Measurement
        <- rtn as Integer: amount <=> other.amount

      default operator ==

      operator $ as pure
        <- rtn as String: $amount

      operator #? as pure
        <- rtn as Integer: #? amount

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

    //Child overrides operators
    Weight extends Measurement
      Weight()
        -> amount as Float
        super(amount)

      //Override string representation
      override operator $ as pure
        <- rtn as String: `${amount()} kg`

      default operator ?

    Length extends Measurement
      Length()
        -> amount as Float
        super(amount)

      override operator $ as pure
        <- rtn as String: `${amount()} m`

      default operator ?

  defines program

    OverrideOperatorDemo()
      stdout <- Stdout()

      weight <- Weight(75.5)
      stdout.println(`Weight: ${weight}`)

      lengthVal <- Length(1.82)
      stdout.println(`Length: ${lengthVal}`)

      //Comparison works through parent operator
      stdout.println(`Compare: ${weight <=> Weight(80.0)}`)
      stdout.println(`Equal: ${weight == Weight(75.5)}`)

Java: no operator overloading. Kotlin: operator overloading exists, override keyword applies. C#: operator overloading but no inheritance override. EK9: operators follow identical override rules to methods, 'override operator' syntax.

abstract child comparison default inherit isSet open operator override string virtual

Explanation: When the parent class defines operator $, the child must use override operator $ to replace it. Omitting override on operator overrides triggers shadowing detection. See ek9 -h E05120 for details.

Explanation: The parent operator $ is pure, so the child override must also be pure. Removing purity from the override violates the purity contract. See ek9 -h E07500 for details.


Question: What is the relationship between open, abstract, and override?

How do open and abstract interact with override?

How do I design a class hierarchy for extension?

Answer:
In EK9, three modifiers control method overriding: 'as open' makes a class extensible, 'as abstract' makes a class extensible with incomplete methods, and 'override' declares intent to replace.

CLOSED (DEFAULT)
Classes without 'as open' or 'as abstract' cannot be extended. Their methods cannot be overridden.

AS OPEN
Makes a class extensible. All public and protected methods become overridable in children:
  Widget as open
    draw() ...
Children can override draw() with 'override draw()'.

AS ABSTRACT
Makes a class extensible with some methods having no body:
  Shape as abstract
    area() as abstract
      <- rtn as Float?
Children MUST override abstract methods.

OVERRIDE CHAINS
A child that is 'as open' allows further overriding:
  Base as open -> Child extends Base as open -> GrandChild extends Child
Each level can override.

A child WITHOUT 'as open' stops the chain:
  Base as open -> FinalChild extends Base
FinalChild's methods cannot be overridden further.

See Q101 for closed by default. See Q102 for 'as open'. See Q103 for abstract classes. See Q570 for override basics. See Q575 for deep override chains.

defines module qa.override.openabstract

  defines class

    //Abstract: must be extended, abstract methods must be overridden
    Shape as abstract
      area() as pure abstract
        <- rtn as Float?

      perimeter() as pure abstract
        <- rtn as Float?

      default operator ?

    //Open: can be extended further
    Rectangle extends Shape as open
      rectWidth <- 0.0
      rectHeight <- 0.0

      Rectangle()
        ->
          rectWidth as Float
          rectHeight as Float
        this.rectWidth: rectWidth
        this.rectHeight: rectHeight

      override area() as pure
        <- rtn as Float: rectWidth * rectHeight

      override perimeter() as pure
        <- rtn as Float: 2.0 * (rectWidth + rectHeight)

      rectWidth() as pure
        <- rtn as Float: rectWidth

      rectHeight() as pure
        <- rtn as Float: rectHeight

      default operator ?

    //Closed (default): cannot be extended further
    Square extends Rectangle
      Square()
        -> side as Float
        super(side, side)

      //Can override parent methods
      override area() as pure
        <- rtn as Float: rectWidth() * rectWidth()

      default operator ?

  defines program

    OpenAbstractOverrideDemo()
      stdout <- Stdout()

      square <- Square(5.0)
      stdout.println(`Square area: ${square.area()}`)
      stdout.println(`Square perimeter: ${square.perimeter()}`)

      //Polymorphic use
      shapes <- List() of Shape
      shapes += Rectangle(3.0, 4.0)
      shapes += Square(6.0)

      for shape in shapes
        stdout.println(`Area: ${shape.area()}, Perimeter: ${shape.perimeter()}`)

Java: classes open by default, final to close. Kotlin: classes and methods closed by default, open keyword on both. Swift: class and method level open/final control. EK9: class-level open/abstract, all public methods overridable in open classes.

abstract chain closed design extensible hierarchy inherit open override virtual

Explanation: While extending Shape directly is not circular, Square is designed to reuse Rectangle. If Square tried to extend a type that creates a cycle, E50060 would fire. See ek9 -h E50060 for details.

Explanation: When overriding the abstract area method from Shape, the override keyword is mandatory. Without it, the compiler detects method shadowing. See ek9 -h E05120 for details.

Explanation: The abstract area method in Shape is declared as pure, so every override must also be pure. Removing purity from the override violates the contract. See ek9 -h E05150 for details.


Question: How do overrides work in a three-level trait hierarchy?

Can traits extend other traits with overrides?

How does override work when traits inherit from traits?

What happens with override in a trait chain?

Answer:
Note: override applies to both methods and operators (e.g., override operator ? as pure, override operator $ as pure).

Traits can extend other traits, creating trait inheritance chains. Each level can provide default implementations or declare abstract methods. Classes implementing the final trait must override any remaining abstract methods.

TRAIT EXTENDING TRAIT
A trait can extend another trait using 'is' or 'extends':
  BaseTrait
    method() as abstract ...
  ExtendedTrait is BaseTrait
    override method() ...
    extraMethod() ...

THREE-LEVEL CHAIN
BaseTrait declares abstract methods. MiddleTrait extends BaseTrait and provides defaults. FinalTrait extends MiddleTrait and can override defaults. Classes implement any trait in the chain.

OVERRIDE AT EACH LEVEL
Each trait level that replaces an inherited method must use 'override'. This follows the same rules as class overrides.

CLASS IMPLEMENTATION
A class implementing the final trait must override any remaining abstract methods. Methods with defaults can optionally be overridden.

See Q106 for trait basics. See Q107 for multiple traits. See Q570 for override basics. See Q576 for class and trait override.
See Q676 for override access hierarchy. See Q680 for diamond trait resolution.

defines module qa.override.traitchain

  defines trait

    //Level 1: base trait
    Identifiable
      identity() as pure abstract
        <- rtn as String?

    //Level 2: extends base, adds methods
    Displayable is Identifiable
      format() as pure
        <- rtn as String: `[${identity()}]`

    //Level 3: extends middle, can override defaults
    Loggable is Displayable
      override format() as pure
        <- rtn as String: "LOG:" + identity()

      severity() as pure
        <- rtn as String: "INFO"

  defines class

    //Implements final trait: must override remaining abstract
    LogEntry with trait of Loggable
      message <- String()

      LogEntry()
        -> message as String
        this.message: message

      //Must override: abstract from Identifiable
      override identity() as pure
        <- rtn as String: message

      //Can optionally override: default from Loggable
      override severity() as pure
        <- rtn as String: "WARN"

      default operator ?

    //Another implementation keeping defaults
    AuditEntry with trait of Loggable
      action <- String()

      AuditEntry()
        -> action as String
        this.action: action

      //Must override abstract from Identifiable
      override identity() as pure
        <- rtn as String: action

      //Keeps default severity ("INFO") and format ("LOG:...")
      default operator ?

  defines program

    ThreeLevelTraitChainDemo()
      stdout <- Stdout()

      logItem <- LogEntry("disk full")
      stdout.println(`${logItem.format()} [${logItem.severity()}]`)

      auditItem <- AuditEntry("user login")
      stdout.println(`${auditItem.format()} [${auditItem.severity()}]`)

Java: interfaces can extend other interfaces, default methods since Java 8. Kotlin: interfaces can extend interfaces with defaults. Rust: trait inheritance with supertraits. EK9: trait extending trait with 'is' or 'extends', override required at each level.

abstract chain default extend hierarchy inherit open override three-level trait virtual

Explanation: Implementing the abstract identity method from Identifiable requires the override keyword. Omitting it triggers shadowing detection. See ek9 -h E05120 for details.

Explanation: Claiming override on a method name that does not exist in any trait in the chain is a false override claim. Only methods defined in the trait hierarchy can be overridden. See ek9 -h E05110 for details.


Question: How do I call one constructor from another using this()?

How does constructor chaining work in EK9?

How do I delegate between constructors with this()?

Answer:
Use this() as the first statement in a constructor to delegate to another constructor of the same class. This avoids duplicating initialization logic.

BASIC DELEGATION
Call this() with arguments matching another constructor:
  Account()
    -> name as String
    this(name, 0.0)  //delegates to two-arg constructor
  Account()
    -> name as String, balance as Float
    this.name: name
    this.balance: balance

MUST BE FIRST STATEMENT
this() must be the very first statement in the constructor body. No code can execute before delegation (E05050).

CHAINING MULTIPLE
Constructors can chain through multiple levels:
  Account() -> this("anonymous") -> this("anonymous", 0.0)
Each level delegates to a more specific constructor.

NO CIRCULAR DELEGATION
Constructor chains must terminate. A circular chain (A calls B calls A) is a compile error.

See Q581 for super() delegation. See Q582 for delegation order rules. See Q583 for this() vs super() restrictions. See Q94 for constructor basics. See Q605 for why 'this' is invalid in standalone functions.

defines module qa.constructor.thisdelegation

  defines class

    Account
      holder <- String()
      balance <- 0.0
      accountType <- String()

      //One-arg delegates to two-arg
      Account()
        -> holder as String
        this(holder, 0.0)

      //Two-arg delegates to three-arg
      Account()
        ->
          holder as String
          balance as Float
        this(holder, balance, "standard")

      //Three-arg: does the actual initialization
      Account()
        ->
          holder as String
          balance as Float
          accountType as String
        this.holder: holder
        this.balance: balance
        this.accountType: accountType

      holder() as pure
        <- rtn as String: holder

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

      accountType() as pure
        <- rtn as String: accountType

      default operator ?

  defines program

    ThisDelegationDemo()
      stdout <- Stdout()

      //Uses one-arg constructor (delegates through chain)
      acc1 <- Account("Alice")
      stdout.println(`${acc1.holder()}: ${acc1.balance()} (${acc1.accountType()})`)

      //Uses two-arg constructor
      acc2 <- Account("Bob", 100.0)
      stdout.println(`${acc2.holder()}: ${acc2.balance()} (${acc2.accountType()})`)

      //Uses three-arg constructor directly
      acc3 <- Account("Charlie", 500.0, "premium")
      stdout.println(`${acc3.holder()}: ${acc3.balance()} (${acc3.accountType()})`)

Java: this() constructor chaining, must be first statement. Python: no this() equivalent. Kotlin: primary constructor + this() delegation. C#: this() chaining, must be first. EK9: this() delegation with first-statement rule, E05050 if not first.

E05050 chain constant constructor delegation first statement super this

Account()
        -> holder as String
        this.holder: holder
        this(holder, 0.0)

Explanation: The this() delegation call must be the very first statement in the constructor body. No field assignments or other code can appear before it. See ek9 -h E05050 for details.


Question: How do I call a parent constructor using super()?

How does super() work in EK9 constructors?

How do I initialize the parent class in a constructor?

Answer:
Use super() as the first statement in a child class constructor to call the parent class constructor. This ensures the parent is properly initialized before the child adds its own state.

BASIC SUPER() CALL
Call super() with arguments matching a parent constructor:
  Child()
    -> name as String, age as Integer
    super(name)  //calls Parent(String) constructor
    this.age: age

MUST BE FIRST STATEMENT
super() must be the first statement in the constructor body (E05050). No code can execute before the parent is initialized.

REQUIRES EXPLICIT PARENT
super() is only valid when the class explicitly extends another class. Using super() without an explicit parent produces E05040.

PARAMETER PASSING
Pass the appropriate arguments to match the parent constructor:
  ChildClass()
    -> a as String, b as Integer
    super(a)  //passes 'a' to parent constructor

See Q580 for this() delegation. See Q582 for delegation order. See Q583 for this() vs super() restrictions. See Q584 for missing super() call.

defines module qa.constructor.superdelegation

  defines class

    //Parent class: must be open for extension
    Entity as open
      entityName <- String()

      Entity()
        -> entityName as String
        this.entityName: entityName

      entityName() as pure
        <- rtn as String: entityName

      default operator ?

    //Child calls super() to initialize parent
    Person extends Entity as open
      personAge <- 0

      Person()
        ->
          entityName as String
          personAge as Integer
        super(entityName)
        this.personAge: personAge

      personAge() as pure
        <- rtn as Integer: personAge

      default operator ?

    //Grandchild also uses super()
    Employee extends Person
      role <- String()

      Employee()
        ->
          entityName as String
          personAge as Integer
          role as String
        super(entityName, personAge)
        this.role: role

      role() as pure
        <- rtn as String: role

      default operator ?

  defines program

    SuperDelegationDemo()
      stdout <- Stdout()

      entity <- Entity("Base")
      stdout.println(`Entity: ${entity.entityName()}`)

      person <- Person("Alice", 30)
      stdout.println(`Person: ${person.entityName()}, age ${person.personAge()}`)

      emp <- Employee("Bob", 25, "Developer")
      stdout.println(`Employee: ${emp.entityName()}, age ${emp.personAge()}, role ${emp.role()}`)

Java: super() must be first statement, implicit if parent has no-arg constructor. Python: super().__init__() can be called anywhere. Kotlin: primary constructor delegates via super in class header. C#: base() constructor chaining. EK9: super() must be first statement, E05050 if not, E05040 if no explicit parent.

E05040 E05050 constant constructor delegation first initialize parent super this

Person()
        ->
          entityName as String
          personAge as Integer
        this.personAge: personAge
        super(entityName)

Explanation: The super() call must be the very first statement in the constructor body. No field assignments can appear before the parent is initialized. See ek9 -h E05050 for details.

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


Question: Why must this() or super() be the first statement in a constructor?

What is E05050 delegation not first statement?

Can I run code before this() or super()?

Why does my constructor delegation fail with E05050?

Answer:
In EK9, this() or super() must be the very first statement in a constructor body. Any code before the delegation call produces error E05050.

THE RULE
Delegation calls (this() or super()) must be the first executable statement. No variable assignments, method calls, or assertions can come before them.

THE ERROR: E05050
E05050 fires when code appears before this() or super(). The compiler requires delegation to happen before any other logic.

WHY FIRST STATEMENT
Object initialization order must be predictable. The parent (or delegated constructor) sets up fundamental state. Child code runs after the base is established. This prevents accessing uninitialized parent state.

CORRECT PATTERN
Put all validation and logic AFTER the delegation:
  Child()
    -> value as Integer
    super(value)       // First statement
    assert value > 0   // Validation after

PARAMETER VALIDATION
If you need to validate parameters before construction, use a factory function or validate in the delegated constructor itself.

See Q580 for this() delegation. See Q581 for super() delegation. See Q583 for this() vs super() restrictions.

defines module qa.constructor.delegationorder

  defines class

    Base as open
      label <- String()

      Base()
        -> label as String
        this.label: label

      label() as pure
        <- rtn as String: label

      default operator ?

    //Correct: super() is the first statement
    Derived extends Base
      priority <- 0

      Derived()
        ->
          label as String
          priority as Integer
        super(label)
        this.priority: priority

      //Another constructor: this() is the first statement
      Derived()
        -> label as String
        this(label, 1)

      priority() as pure
        <- rtn as Integer: priority

      default operator ?

  defines program

    DelegationOrderDemo()
      stdout <- Stdout()

      item1 <- Derived("alpha", 5)
      stdout.println(`${item1.label()}: priority ${item1.priority()}`)

      item2 <- Derived("beta")
      stdout.println(`${item2.label()}: priority ${item2.priority()}`)

Java: this()/super() must be first statement (relaxed in Java 22). Python: super().__init__() can be anywhere. Kotlin: primary constructor handles this implicitly. C#: base()/this() must be in constructor header. EK9: E05050 enforces first-statement rule strictly.

E05050 constant constructor delegation first order statement super this

Derived()
        ->
          label as String
          priority as Integer
        this.priority: priority
        super(label)

Explanation: The super() call must be the very first statement. Assigning fields before calling super() means the parent is not yet initialized, which is invalid. See ek9 -h E05050 for details.

Derived()
        -> label as String
        priority: 1
        this(label, 1)

Explanation: The this() delegation must be the first statement. No variable assignments or other code can precede it. See ek9 -h E05050 for details.


Question: Can I use both this() and super() in the same constructor?

Why can't I call both this() and super()?

Can a constructor delegate to both this() and super()?

Answer:
No. A constructor can use either this() or super(), but not both. Since delegation must be the first statement, only one delegation call is possible per constructor.

THE RULE
A constructor body can contain at most one delegation call: either this() or super(), never both. E05060 covers the use of this()/super() outside constructors; in practice, the first-statement rule (E05050) prevents having both.

CORRECT PATTERN: SEPARATE CONSTRUCTORS
Use separate constructors for different delegation paths:
  Child()
    -> name as String
    this(name, 0)          // this() delegation
  Child()
    -> name as String, count as Integer
    super(name)            // super() delegation
    this.count: count

The one-arg constructor delegates to the two-arg constructor via this(), and the two-arg constructor delegates to the parent via super(). Each constructor has exactly one delegation target.

See Q580 for this() delegation. See Q581 for super() delegation. See Q582 for delegation order. See Q585 for field initialization vs delegation.

defines module qa.constructor.notboth

  defines class

    Animal as open
      species <- String()

      Animal()
        -> species as String
        this.species: species

      species() as pure
        <- rtn as String: species

      default operator ?

    //Correct: this() and super() in SEPARATE constructors
    Pet extends Animal
      petName <- String()

      //This constructor uses this() delegation
      Pet()
        -> petName as String
        this(petName, "Unknown")

      //This constructor uses super() delegation
      Pet()
        ->
          petName as String
          species as String
        super(species)
        this.petName: petName

      petName() as pure
        <- rtn as String: petName

      default operator ?

  defines program

    NotBothDemo()
      stdout <- Stdout()

      //Uses this() path
      pet1 <- Pet("Buddy")
      stdout.println(`${pet1.petName()} is a ${pet1.species()}`)

      //Uses super() path directly
      pet2 <- Pet("Max", "Dog")
      stdout.println(`${pet2.petName()} is a ${pet2.species()}`)

Java: same rule, cannot have both this() and super(). Kotlin: primary constructor handles implicit super. C#: same rule, choose this() or base(). EK9: same rule, one delegation per constructor.

E05060 both constant constructor delegation exclusive mutual super this

Pet()
        -> petName as String
        this(petName, "Unknown")
        super("Cat")

Explanation: A constructor can use either this() or super(), but not both. Since delegation must be the first statement, only one delegation call is possible per constructor. See ek9 -h E05050 for details.

Pet()
        ->
          petName as String
          species as String
        this.petName: petName
        super(species)

Explanation: The super() delegation must be the first statement in the constructor body. Field assignments cannot appear before it. See ek9 -h E05050 for details.


Question: When is an explicit super() call required?

What is E05080 super without explicit parent?

When must I call super() in a constructor?

Answer:
super() is only needed when the parent class requires constructor arguments. If the parent has a default (no-arg) constructor, EK9 implicitly calls it. E05040 fires if you call super() without an explicit parent class. E05080 fires if you use 'super' outside a class with an explicit parent.

WHEN SUPER() IS NEEDED
When the parent class only has constructors with parameters, the child must explicitly call super() with the right arguments. Without it, the parent cannot be initialized.

WHEN SUPER() IS IMPLICIT
If the parent has a no-arg constructor (or a default constructor), and the child constructor does not explicitly call super(), the parent no-arg constructor is called implicitly.

E05040: NO EXPLICIT PARENT
If you call super() in a class that does not explicitly extend another class, the compiler reports E05040.

E05080: SUPER WITHOUT PARENT
If you use 'super' (the keyword, not just the call) in a class that does not extend another, the compiler reports E05080.

See Q580 for this() delegation. See Q581 for super() basics. See Q582 for delegation order. See Q587 for multi-level constructor hierarchies.

defines module qa.constructor.missingsuper

  defines class

    //Parent with required parameter: child MUST call super()
    NamedEntity as open
      entityName <- String()

      NamedEntity()
        -> entityName as String
        this.entityName: entityName

      entityName() as pure
        <- rtn as String: entityName

      default operator ?

    //Child must call super() because parent has no default constructor
    TaggedEntity extends NamedEntity
      tag <- String()

      TaggedEntity()
        ->
          entityName as String
          tag as String
        super(entityName)
        this.tag: tag

      tag() as pure
        <- rtn as String: tag

      default operator ?

    //Parent with default constructor: super() is implicit
    SimpleBase as open
      default SimpleBase()

      baseLabel() as pure
        <- rtn as String: "simple"

      default operator ?

    //Child does not need explicit super() call
    SimpleDerived extends SimpleBase
      derivedLabel <- String()

      SimpleDerived()
        -> derivedLabel as String
        //No super() needed: SimpleBase() is called implicitly
        this.derivedLabel: derivedLabel

      derivedLabel() as pure
        <- rtn as String: derivedLabel

      default operator ?

  defines program

    MissingSuperCallDemo()
      stdout <- Stdout()

      //Explicit super() required
      tagged <- TaggedEntity("Server", "production")
      stdout.println(`${tagged.entityName()}: ${tagged.tag()}`)

      //Implicit super() (no-arg parent)
      simple <- SimpleDerived("extra")
      stdout.println(`${simple.baseLabel()}: ${simple.derivedLabel()}`)

Java: implicit super() if parent has no-arg constructor. Python: must explicitly call super().__init__(). Kotlin: delegation in class header. C#: implicit base() if no-arg exists. EK9: implicit no-arg super(), explicit required when parent needs arguments, E05040/E05080 for incorrect use.

E05040 E05080 constructor delegation explicit implicit missing parent super this

TaggedEntity()
        ->
          entityName as String
          tag as String
        this.tag: tag
        super(entityName)

Explanation: The super() call must be the first statement. The parent must be fully initialized before the child assigns its own fields. See ek9 -h E05050 for details.


Question: How do field initialization and constructor delegation interact?

When should I use field defaults vs constructor assignment?

How do inline field values work with constructors?

What is the field initialization order in EK9?

Answer:
Fields in EK9 must be initialized inline at declaration. Constructors then optionally reassign fields using ':' or ':=?'. Understanding the interaction between field defaults and constructor assignment is essential.

FIELD DEFAULTS
Every field must have an inline default:
  name <- String()    //initialized to unset String
  count <- 0          //initialized to 0
Fields cannot be left uninitialized (E08180).

CONSTRUCTOR ASSIGNMENT
Constructors use ':' to reassign fields after defaults are applied:
  MyClass()
    -> name as String
    this.name: name  //reassigns from default to parameter

ORDER OF INITIALIZATION
Field defaults are applied when the object is created. Then the constructor body runs. If delegation is used, the delegated constructor runs first.

COMBINING WITH DELEGATION
When using this() or super(), field defaults apply first, then the delegated constructor runs, then remaining statements in the calling constructor.

See Q580 for this() delegation. See Q581 for super() delegation. See Q104 for uninitialized properties. See Q563 for pure constructor field assignment.

defines module qa.constructor.fieldinit

  defines class

    //Fields with defaults, constructors reassign
    Configuration
      hostname <- "localhost"
      portNumber <- 8080
      maxRetries <- 3

      //One-arg: only changes hostname
      Configuration()
        -> hostname as String
        this.hostname: hostname

      //Two-arg: changes hostname and port
      Configuration()
        ->
          hostname as String
          portNumber as Integer
        this.hostname: hostname
        this.portNumber: portNumber

      //Three-arg: changes all fields
      Configuration()
        ->
          hostname as String
          portNumber as Integer
          maxRetries as Integer
        this.hostname: hostname
        this.portNumber: portNumber
        this.maxRetries: maxRetries

      hostname() as pure
        <- rtn as String: hostname

      portNumber() as pure
        <- rtn as Integer: portNumber

      maxRetries() as pure
        <- rtn as Integer: maxRetries

      default operator ?

  defines program

    FieldInitDelegationDemo()
      stdout <- Stdout()

      //One-arg: port and retries keep defaults
      cfg1 <- Configuration("api.example.com")
      stdout.println(`${cfg1.hostname()}: ${cfg1.portNumber()}, retries ${cfg1.maxRetries()}`)

      //Two-arg: retries keeps default
      cfg2 <- Configuration("db.example.com", 5432)
      stdout.println(`${cfg2.hostname()}: ${cfg2.portNumber()}, retries ${cfg2.maxRetries()}`)

      //Three-arg: all custom
      cfg3 <- Configuration("cache.example.com", 6379, 5)
      stdout.println(`${cfg3.hostname()}: ${cfg3.portNumber()}, retries ${cfg3.maxRetries()}`)

Java: fields can be uninitialized (get default zero/null values). Python: fields set in __init__. Kotlin: properties initialized in init block or primary constructor. EK9: fields must be initialized inline, E08180 if not, constructors reassign with ':'.

E08180 constant constructor default delegation field initialization inline order super this

hostname <- portNumber
      portNumber <- 8080

Explanation: Using a field before it has been declared is a forward reference error. Fields must be declared before being referenced. See ek9 -h E04050 for details.


Question: How does constructor delegation work with pure constructors?

Can pure constructors use this() and super()?

How do I chain pure constructors with delegation?

What are the rules for pure constructor delegation?

Answer:
Pure constructors can use both this() and super() delegation, following the same first-statement rule. The key requirement is that ALL constructors must be consistently pure (E05190).

PURE THIS() DELEGATION
Pure constructors can delegate to another pure constructor with this():
  Config() as pure
    -> host as String
    this(host, 8080)
  Config() as pure
    -> host as String, port as Integer
    this.host :=? host
    this.port :=? port

PURE SUPER() DELEGATION
Pure child constructors can call pure parent constructors with super():
  Child() as pure
    -> name as String, extra as Integer
    super(name)
    this.extra :=? extra

CONSISTENCY REQUIREMENT
If the parent has pure constructors, and you extend it, your constructors must also be pure. If the parent has non-pure constructors, your constructors must also be non-pure.

GUARDED ASSIGNMENT
Pure constructors use ':=?' for field assignment after delegation. The delegated constructor may have already set some fields.

See Q563 for pure constructor basics. See Q564 for all-or-nothing purity. See Q565 for multiple pure constructors. See Q580 for this() delegation.

defines module qa.constructor.puredelegation

  defines class

    //Parent with pure constructors
    Coordinates as open
      latitude as Float: Float()
      longitude as Float: Float()

      Coordinates() as pure
        ->
          latitude as Float
          longitude as Float
        this.latitude :=? latitude
        this.longitude :=? longitude

      latitude() as pure
        <- rtn as Float: latitude

      longitude() as pure
        <- rtn as Float: longitude

      default operator ?

    //Child: pure constructors with both this() and super()
    Location extends Coordinates
      locationName <- String()

      //this() delegation in pure constructor
      Location() as pure
        -> locationName as String
        this(locationName, 0.0, 0.0)

      //super() delegation in pure constructor
      Location() as pure
        ->
          locationName as String
          latitude as Float
          longitude as Float
        super(latitude, longitude)
        this.locationName :=? locationName

      locationName() as pure
        <- rtn as String: locationName

      default operator ?

  defines program

    PureConstructorDelegationDemo()
      stdout <- Stdout()

      //this() delegation path
      loc1 <- Location("Unknown")
      stdout.println(`${loc1.locationName()}: (${loc1.latitude()}, ${loc1.longitude()})`)

      //super() delegation path
      loc2 <- Location("London", 51.5074, -0.1278)
      stdout.println(`${loc2.locationName()}: (${loc2.latitude()}, ${loc2.longitude()})`)

Java: no pure constructor concept. Kotlin: no constructor purity. EK9: pure constructors support this() and super() delegation, all constructors must be consistently pure (E05190), :=? for field assignment.

E05190 chain constant constructor delegation guarded immutable isset null-safe pure safe side-effect super this

Location()
        -> locationName as String
        this(locationName, 0.0, 0.0)

Explanation: If any constructor is pure, ALL constructors must be pure. Mixing pure and non-pure constructors in the same class is invalid. See ek9 -h E05190 for details.

Location() as pure
        ->
          locationName as String
          latitude as Float
          longitude as Float
        this.locationName :=? locationName
        super(latitude, longitude)

Explanation: Even in pure constructors, super() must be the first statement. No field assignments can precede the parent delegation. See ek9 -h E05050 for details.


Question: How do constructors work in multi-level class hierarchies?

How do I pass parameters through a three-level constructor chain?

How does super() work with grandparent constructors?

What is the constructor pattern for deep hierarchies?

Answer:
In multi-level hierarchies, each level uses super() to initialize its immediate parent. Parameters flow from the most derived class through each parent in the chain.

THREE-LEVEL PATTERN
Grandparent defines base fields and constructor. Parent extends grandparent, adds fields, calls super() to grandparent. Child extends parent, adds fields, calls super() to parent. Each level only passes what its parent needs.

PARAMETER FLOW
Child receives all parameters and passes a subset to parent:
  Employee(name, age, role)
    super(name, age)  //Person gets name and age
  Person(name, age)
    super(name)        //Entity gets name
  Entity(name)
    this.name: name    //stores name

EACH LEVEL INITIALIZES ITS OWN STATE
Each constructor calls super() with the parent's parameters, then initializes its own fields. This keeps each class responsible for its own state.

DEFAULT CONSTRUCTORS IN THE CHAIN
If any level has a default constructor, the child does not need explicit super() for that level.

See Q580 for this() delegation. See Q581 for super() delegation. See Q582 for delegation order. See Q575 for deep override chains.

defines module qa.constructor.hierarchy

  defines class

    //Level 1: base entity
    Entity as open
      entityName <- String()

      Entity()
        -> entityName as String
        this.entityName: entityName

      entityName() as pure
        <- rtn as String: entityName

      default operator ?

    //Level 2: adds age
    Person extends Entity as open
      personAge <- 0

      Person()
        ->
          entityName as String
          personAge as Integer
        super(entityName)
        this.personAge: personAge

      personAge() as pure
        <- rtn as Integer: personAge

      default operator ?

    //Level 3: adds department
    Employee extends Person
      department <- String()

      Employee()
        ->
          entityName as String
          personAge as Integer
          department as String
        super(entityName, personAge)
        this.department: department

      department() as pure
        <- rtn as String: department

      default operator ?

  defines program

    HierarchyConstructorsDemo()
      stdout <- Stdout()

      emp <- Employee("Alice", 30, "Engineering")
      stdout.println(`Name: ${emp.entityName()}`)
      stdout.println(`Age: ${emp.personAge()}`)
      stdout.println(`Dept: ${emp.department()}`)

      //Polymorphic use
      entities <- List() of Entity
      entities += Entity("Base")
      entities += Person("Bob", 25)
      entities += Employee("Charlie", 35, "Sales")

      for entity in entities
        stdout.println(`Entity: ${entity.entityName()}`)

Java: same pattern, super() in each level. Python: super().__init__() chains through MRO. Kotlin: primary constructor in class header handles delegation. C#: base() at each level. EK9: super() at each level, parameters flow through chain.

chain class constant constructor delegation flow grandparent hierarchy multi-level parameter super this

Employee()
        ->
          entityName as String
          personAge as Integer
          department as String
        this.department: department
        super(entityName, personAge)

Explanation: super() must be the first statement in the constructor. The parent (Person) must be initialized before the child (Employee) assigns its own fields. See ek9 -h E05050 for details.


Question: How do functions extend other functions in EK9?

How does function inheritance work in EK9?

Can functions extend abstract functions?

Answer:
In EK9, functions are types that can participate in type hierarchies. A concrete function can extend an abstract function using 'is' or 'extends'. This creates function polymorphism without classes.

FUNCTION EXTENSION SYNTAX
Use 'is' to extend an abstract function:
  Transformer as pure abstract
    -> input as String
    <- result as String?

  UpperTransformer is Transformer as pure
    -> input as String
    <- result as String: input.upperCase()

WHY THIS IS UNIQUE
In most languages, callable polymorphism requires classes, interfaces, or trait objects. EK9 functions are TYPES with identity: they can be stored, passed, and collected in lists. Function extension gives you polymorphism without any class boilerplate.

SIGNATURE MATCHING
The extending function must match the abstract function's signature: same parameter types and compatible return type. Mismatches produce E05140.

See Q51 for abstract functions. See Q49 for function basics. See Q589 for abstract function implementations. See Q592 for signature mismatch errors.

defines module qa.function.extensionbasics

  defines function

    //Abstract function: defines the contract
    Transformer as pure abstract
      -> input as String
      <- result as String?

    //Concrete function extends abstract
    UpperTransformer is Transformer as pure
      -> input as String
      <- result as String: input.upperCase()

    //Another implementation
    PrefixTransformer is Transformer as pure
      -> input as String
      <- result as String: "PREFIX:" + input

    //Yet another implementation
    LengthTransformer is Transformer as pure
      -> input as String
      <- result as String: $length input

  defines program

    FunctionExtensionBasicsDemo()
      stdout <- Stdout()

      //Direct calls
      stdout.println(UpperTransformer("hello"))
      stdout.println(PrefixTransformer("world"))
      stdout.println(LengthTransformer("test"))

      //Polymorphic use through abstract type
      transformers <- List() of Transformer
      transformers += UpperTransformer
      transformers += PrefixTransformer
      transformers += LengthTransformer

      for transformer in transformers
        stdout.println(transformer("ek9"))

Java: functional interfaces + lambda, no function type hierarchies. Python: no function typing. Rust: Fn traits are structural, not nominal. Go: function types exist but no inheritance. Kotlin: functional types are structural. Swift: closures are structural types, extensions add methods to existing types but no function type hierarchies. EK9: functions are nominal types with 'is'/'extends' hierarchies, unique function polymorphism.

abstract extend extends extension function handler hierarchy is polymorphism sealed swift type visitor

function extension
extend function
function hierarchy

UpperTransformer is Transformer
      -> input as String
      <- result as String: input.upperCase()

Explanation: When the abstract function is pure, all extending functions must also be pure. Omitting 'as pure' violates the purity contract and triggers E05150 because 'pure' in super requires 'pure' for the extending definition. See ek9 -h E05150 for details.


Question: How do I implement an abstract function with multiple implementations?

How do I create multiple function implementations?

Can I have several functions extending the same abstract?

How do I use abstract functions for strategy pattern?

Answer:
An abstract function can have any number of concrete implementations. Each implementation uses 'is' to extend the abstract and must match the signature exactly.

MULTIPLE IMPLEMENTATIONS
Define the abstract once, implement many times:
  MathOp as pure abstract
    -> a as Float, b as Float
    <- result as Float?

  AddOp is MathOp as pure
    -> a as Float, b as Float
    <- result as Float: a + b

  SubOp is MathOp as pure
    -> a as Float, b as Float
    <- result as Float: a - b

STRATEGY PATTERN
Store implementations in variables typed as the abstract function:
  currentOp as MathOp: AddOp
  result <- currentOp(10.0, 5.0)
Swap implementations at runtime without classes.

LIST OF FUNCTIONS
Collect implementations for iteration:
  ops <- [AddOp, SubOp, MulOp]
  for op in ops
    stdout.println(op(10.0, 5.0))

See Q588 for function extension basics. See Q51 for abstract functions. See Q214 for strategy pattern. See Q590 for dynamic function implementations.

defines module qa.function.abstractimpl

  defines function

    //Abstract function: math operation contract
    MathOp as pure abstract
      ->
        operandA as Float
        operandB as Float
      <- result as Float?

    AddOp is MathOp as pure
      ->
        operandA as Float
        operandB as Float
      <- result as Float: operandA + operandB

    SubtractOp is MathOp as pure
      ->
        operandA as Float
        operandB as Float
      <- result as Float: operandA - operandB

    MultiplyOp is MathOp as pure
      ->
        operandA as Float
        operandB as Float
      <- result as Float: operandA * operandB

  defines program

    AbstractFunctionImplDemo()
      stdout <- Stdout()

      //Direct calls
      stdout.println(`Add: ${AddOp(10.0, 3.0)}`)
      stdout.println(`Sub: ${SubtractOp(10.0, 3.0)}`)
      stdout.println(`Mul: ${MultiplyOp(10.0, 3.0)}`)

      //Strategy pattern: swap at runtime
      currentOp as MathOp: AddOp
      stdout.println(`Current (add): ${currentOp(5.0, 2.0)}`)

      currentOp: MultiplyOp
      stdout.println(`Current (mul): ${currentOp(5.0, 2.0)}`)

      //List of operations
      operations <- List() of MathOp
      operations += AddOp
      operations += SubtractOp
      operations += MultiplyOp

      for operation in operations
        stdout.println(`Result: ${operation(8.0, 4.0)}`)

Java: strategy pattern requires interface + multiple classes. Python: pass different functions directly (no type checking). Rust: closures with Box<dyn Fn>. Kotlin: functional types + lambda. EK9: abstract function + multiple 'is' implementations, true function polymorphism.

abstract extend function handler implementation list multiple polymorphism sealed strategy swap visitor

AddOp is MathOp as pure
      ->
        operandA as Float
        operandB as Float
      <- result as Float: operandA + operandB
      stdout.println(result)

Explanation: A pure function cannot call non-pure methods like stdout.println(). Pure functions must be side-effect free. See ek9 -h E50001 for details.


Question: Can dynamic functions extend abstract functions?

How do I create inline function implementations?

Can I use dynamic functions with abstract function types?

How do I extend an abstract function inline?

Answer:
Yes, dynamic functions can extend abstract functions. A dynamic function is created inline and implements the abstract function's contract, typically capturing values from the surrounding scope.

DYNAMIC FUNCTION SYNTAX
Create a dynamic function that extends an abstract:
  Formatter as pure abstract
    -> text as String
    <- rtn as String?

  upper <- () is Formatter as pure (rtn:=? text.upperCase())

CLOSURE CAPTURE
Dynamic functions capture values from their enclosing scope. The captured values become part of the function instance:
  tag <- "LOG"
  logger <- (tag) is Formatter as pure function
    rtn:=? tag + ": " + text

INLINE VS MULTI-LINE
Inline form: () is Type as pure (body). Multi-line form: () is Type as pure function followed by indented body.

WHEN TO USE DYNAMIC FUNCTIONS
One-off implementations that do not warrant a named function. Functions that need access to local variables (closures). Building function instances with different captured state.

See Q52 for dynamic function basics. See Q53 for closure capture. See Q588 for function extension basics. See Q591 for comparing function and class hierarchies.

defines module qa.function.dynamicextends

  defines function

    //Abstract function contract
    Formatter as pure abstract
      -> text as String
      <- rtn as String?

    //Named implementation for comparison
    PlainFormatter is Formatter as pure
      -> text as String
      <- rtn as String: text

  defines program

    DynamicFunctionExtendsDemo()
      stdout <- Stdout()

      //Named implementation
      stdout.println(PlainFormatter("hello"))

      //Inline dynamic function (single-line body)
      upper <- () is Formatter as pure (rtn:=? text.upperCase())
      stdout.println(upper("hello"))

      //Dynamic function with captured variable (multi-line body)
      tag <- "LOG"
      logger <- (tag) is Formatter as pure function
        rtn:=? `${tag}: ${text}`

      stdout.println(logger("system started"))

      //Another capture with different value
      errorTag <- "ERROR"
      errorLogger <- (errorTag) is Formatter as pure function
        rtn:=? `${errorTag}: ${text}`

      stdout.println(errorLogger("disk full"))

      //All are Formatter type: polymorphic usage
      formatters <- List() of Formatter
      formatters += PlainFormatter
      formatters += upper
      formatters += logger
      formatters += errorLogger

      for item in formatters
        stdout.println(item("test message"))

Java: lambdas implement functional interfaces. Python: lambdas are limited to expressions. Rust: closures implement Fn traits. Kotlin: lambdas implement functional types. EK9: dynamic functions extend abstract functions with closure capture.

abstract anonymous capture closure dynamic extend extends function implement inline

PlainFormatter is Formatter as pure
      -> text as String
      <- rtn as String: text
      stdout.println(text)

Explanation: A pure function cannot call non-pure methods. Pure functions must not produce side effects. See ek9 -h E50001 for details.


Question: How do function hierarchies compare to class hierarchies?

Should I use function extension or class inheritance?

What is the difference between function and class hierarchies?

When should I prefer functions over classes for polymorphism?

Answer:
Both function hierarchies and class hierarchies provide polymorphism in EK9, but they serve different purposes. Functions are best for stateless transformations; classes are best for stateful entities.

FUNCTION HIERARCHIES
Abstract function defines a callable contract. Concrete functions implement it. No state (unless using closure capture). Best for: transformations, strategies, pipelines, predicates.

CLASS HIERARCHIES
Abstract class defines entity with state and behavior. Concrete classes extend it. Full state management with fields and methods. Best for: domain entities, stateful components, complex objects.

WHEN TO USE FUNCTIONS
Single input-output transformations. Strategy pattern with no shared state. Stream pipeline stages (filter, map, etc.). Predicates and validators.

WHEN TO USE CLASSES
Domain objects with multiple fields. Objects with multiple methods. Stateful services and components. Complex object graphs.

KEY DIFFERENCES
Functions cannot hold mutable state (closures capture values, not variables). Classes can have fields, methods, and operators. Functions are more concise for simple transformations. Classes provide richer abstractions.

See Q588 for function extension. See Q103 for abstract classes. See Q212 for composition over inheritance. See Q214 for strategy pattern.

defines module qa.function.vsclass

  defines constant

    MIN_VALIDATION_LENGTH <- 2

  defines function

    //Function hierarchy: stateless transformation
    Validator as pure abstract
      -> input as String
      <- isValid as Boolean?

    LengthValidator is Validator as pure
      -> input as String
      <- isValid as Boolean: length input > MIN_VALIDATION_LENGTH

    PatternValidator is Validator as pure
      -> input as String
      <- isValid as Boolean: input contains "@"

  defines class

    //Class hierarchy: stateful entity
    Document as abstract
      title <- String()

      Document()
        -> title as String
        this.title: title

      title() as pure
        <- rtn as String: title

      wordCount() as pure abstract
        <- rtn as Integer?

      default operator ?

    TextDocument extends Document
      content <- String()

      TextDocument()
        ->
          title as String
          content as String
        super(title)
        this.content: content

      override wordCount() as pure
        <- rtn as Integer: length content

      default operator ?

  defines program

    FunctionVsClassHierarchyDemo()
      stdout <- Stdout()

      //Function hierarchy: simple validation
      validators <- List() of Validator
      validators += LengthValidator
      validators += PatternValidator

      testInput <- "a@b"
      for validator in validators
        stdout.println(`Valid: ${validator(testInput)}`)

      //Class hierarchy: rich entity
      doc <- TextDocument("Report", "This is the content of the report")
      stdout.println(`${doc.title()}: ${doc.wordCount()} chars`)

Java: interfaces for behavior, classes for state. Python: first-class functions but no type hierarchy. Rust: Fn traits for functions, structs for state. Go: interfaces for behavior, structs for state. EK9: both functions and classes are nominal types with inheritance hierarchies.

abstract class comparison extend function handler hierarchy polymorphism sealed state stateless visitor when

TextDocument()
        ->
          title as String
          content as String
        this.content: content
        super(title)

Explanation: The super() call must be the very first statement in a child class constructor. No code can execute before the parent is initialized. See ek9 -h E05050 for details.

Explanation: When overriding an abstract method from a parent class, the 'override' keyword is required. Omitting it triggers a missing override error. See ek9 -h E05120 for details.


Question: What happens if a function extension has a signature mismatch?

What is E05140 function signature does not match super?

Why does my function extension fail with a signature error?

How do I fix a function signature mismatch?

Answer:
When a function extends an abstract function, the signatures must match. If the parameter types, parameter count, or return type differ, the compiler reports E05140.

THE ERROR: E05140
E05140 fires when a function declares 'is ParentFunction' but the signatures do not match. Common mismatches: different parameter types, wrong parameter count, incompatible return type.

SIGNATURE MATCHING RULES
Parameter count must be identical. Parameter types must be identical (or contravariant). Return type must be identical (or covariant). Parameter names can differ (names are local).

COMMON MISTAKES
Wrong parameter type (Integer vs String). Extra or missing parameters. Return type mismatch.

CORRECT APPROACH
Check the abstract function signature and match it exactly in the implementation. Parameter names can be different, but types must match.

See Q588 for function extension basics. See Q589 for multiple implementations. See Q594 for extension rules.

defines module qa.function.signaturematch

  defines function

    //Abstract with specific signature
    StringProcessor as pure abstract
      -> input as String
      <- output as String?

    //Correct: exact signature match (parameter names differ, types match)
    TrimProcessor is StringProcessor as pure
      -> input as String
      <- output as String: input.trim()

    //Correct: another match
    UpperProcessor is StringProcessor as pure
      -> input as String
      <- output as String: input.upperCase()

    //Different abstract with two parameters
    Combiner as pure abstract
      ->
        first as String
        second as String
      <- combined as String?

    //Correct: matches two-parameter signature
    SpaceCombiner is Combiner as pure
      ->
        first as String
        second as String
      <- combined as String: `${first} ${second}`

    DashCombiner is Combiner as pure
      ->
        first as String
        second as String
      <- combined as String: `${first}-${second}`

  defines program

    FunctionSignatureMatchDemo()
      stdout <- Stdout()

      //Single-parameter functions
      processors <- List() of StringProcessor
      processors += TrimProcessor
      processors += UpperProcessor

      for processor in processors
        stdout.println(processor("  hello  "))

      //Two-parameter functions
      combiners <- List() of Combiner
      combiners += SpaceCombiner
      combiners += DashCombiner

      for combiner in combiners
        stdout.println(combiner("hello", "world"))

Java: functional interface method signature must match exactly. Kotlin: functional type signatures are structural. Rust: closure type must match Fn trait signature. EK9: E05140 enforces exact signature match for function extension.

E05140 abstract count extend function match mismatch parameter return signature type

SpaceCombiner is Combiner as pure
      ->
        first as String
        second as String
      <- combined as String: `${first} ${second}`
      stdout.println(combined)

Explanation: A pure function cannot call non-pure methods. Pure functions must not produce any side effects. See ek9 -h E50001 for details.


Question: Can functions form multi-level inheritance chains?

Can a concrete function be extended further?

Can I have Abstract -> Middle -> Concrete function chains?

Answer:
EK9 functions can form multi-level chains: an abstract function at the top, with concrete implementations at each level. However, only abstract functions can be extended. A concrete function cannot be further extended.

ABSTRACT FUNCTION EXTENSION
Abstract functions define contracts that concrete functions implement:
  BaseOp as pure abstract
    -> x as Integer
    <- rtn as Integer?
  DoubleOp is BaseOp as pure
    -> x as Integer
    <- rtn as Integer: x + x

CONCRETE FUNCTIONS ARE CLOSED
Once a function provides an implementation (has a body), it cannot be extended further. Only abstract functions can be the base of a hierarchy.

MULTIPLE IMPLEMENTATIONS
An abstract function can have many direct implementations, creating a flat hierarchy with one abstract parent and multiple concrete children.

See Q588 for function extension basics. See Q589 for multiple implementations. See Q594 for extension rules. See Q595 for pure abstract function constraints.

defines module qa.function.multilevelchain

  defines constant

    MIN_FILTER_LENGTH <- 3

  defines function

    //Abstract function: base of hierarchy
    Filter as pure abstract
      -> input as String
      <- passes as Boolean?

    //Multiple direct implementations (flat hierarchy)
    NonEmptyFilter is Filter as pure
      -> input as String
      <- passes as Boolean: length input > 0

    LongEnoughFilter is Filter as pure
      -> input as String
      <- passes as Boolean: length input > MIN_FILTER_LENGTH

    ContainsAtFilter is Filter as pure
      -> input as String
      <- passes as Boolean: input contains "@"

  defines program

    MultilevelFunctionChainDemo()
      stdout <- Stdout()

      //All implementations share the abstract type
      filters <- List() of Filter
      filters += NonEmptyFilter
      filters += LongEnoughFilter
      filters += ContainsAtFilter

      testValues <- ["", "hi", "hello", "user@host"]

      for testVal in testValues
        stdout.println(`Testing: "${testVal}"`)
        for filterFn in filters
          stdout.println(`  Passes: ${filterFn(testVal)}`)

Java: functional interfaces are flat (one method). Kotlin: function types are structural. Rust: Fn traits have no hierarchy. EK9: abstract functions can have multiple concrete implementations, concrete functions are closed.

abstract chain closed concrete extend extension function hierarchy multi-level

NonEmptyFilter is Filter as pure
      -> input as String
      <- passes as Boolean: length input > 0
      stdout.println(input)

Explanation: A pure function cannot call non-pure methods like stdout.println(). Pure functions must have no side effects. See ek9 -h E50001 for details.


Question: What are the rules for when a function can or cannot be extended?

What functions can be used as a base type?

Answer:
Only abstract functions can be extended. Concrete functions (those with an implementation body) are closed and cannot serve as a base for other functions.

CAN EXTEND: ABSTRACT FUNCTIONS
Functions declared with 'as abstract' can be extended:
  Predicate as pure abstract
    -> item as String
    <- result as Boolean?

CANNOT EXTEND: CONCRETE FUNCTIONS
Functions with a body cannot be extended:
  addOne() as pure
    -> x as Integer
    <- rtn as Integer: x + 1
  //Cannot write: DoubleAddOne is addOne

SIGNATURE MUST MATCH (E05140)
The extending function must match the abstract function's parameter types, count, and return type. Mismatches produce E05140.

PURITY MUST BE COMPATIBLE
If the abstract function is pure, implementations must be pure (same E05150 rule as classes). If the abstract function is not pure, implementations can be either.

See Q588 for function extension basics. See Q592 for signature mismatch. See Q593 for multi-level chains. See Q595 for pure abstract function constraints.

defines module qa.function.extensionrules

  defines function

    //Abstract: CAN be extended
    Converter as pure abstract
      -> input as Integer
      <- output as String?

    //Implementation 1
    DecimalConverter is Converter as pure
      -> input as Integer
      <- output as String: $input

    //Implementation 2
    HexConverter is Converter as pure
      -> input as Integer
      <- output as String: "0x" + $input

    //Concrete function: CANNOT be extended
    doubleIt() as pure
      -> number as Integer
      <- result as Integer: number + number

  defines program

    FunctionExtensionRulesDemo()
      stdout <- Stdout()

      //Abstract function implementations
      converters <- List() of Converter
      converters += DecimalConverter
      converters += HexConverter

      for converter in converters
        stdout.println(converter(255))

      //Concrete function: used directly
      stdout.println(`Double 5: ${doubleIt(5)}`)

Java: functional interfaces can only have one abstract method. Kotlin: function types are structural, no extension. Rust: no function type inheritance. EK9: only abstract functions can be extended, concrete functions are closed, E05140 for signature mismatch.

E05140 E05150 abstract closed concrete extend extension function immutable purity rules side-effect

doubleIt() as pure
      -> number as Integer
      <- result as Integer: number + number
      stdout.println(result)

Explanation: A pure function cannot call non-pure methods. The 'as pure' contract forbids all side effects. See ek9 -h E50001 for details.


Question: How does purity interact with abstract function extension?

Must implementations of a pure abstract function be pure?

How does purity flow through function hierarchies?

Answer:
If an abstract function is declared 'as pure', every implementation must also be 'as pure'. This is the same E05150 rule that applies to class method overrides. Purity is a contract from the abstract definition.

PURE ABSTRACT FUNCTION
When an abstract function is pure, the contract guarantees no side effects for all implementations:
  Hasher as pure abstract
    -> input as String
    <- hash as Integer?

IMPLEMENTATIONS MUST BE PURE
Every function using 'is Hasher' must also be pure:
  SimpleHasher is Hasher as pure
    -> input as String
    <- hash as Integer: #? input

CANNOT ADD PURITY
If the abstract function is NOT pure, implementations cannot add purity (E05160). Purity flows from the abstract definition.

WHY PURITY MATTERS FOR FUNCTIONS
Code using the abstract type expects consistent behavior. If some implementations are pure and others are not, callers cannot reason about side effects.

See Q560 for pure method basics. See Q561 for purity in overrides. See Q588 for function extension basics. See Q594 for extension rules.

defines module qa.function.pureabstract

  defines function

    //Pure abstract: all implementations must be pure
    Scorer as pure abstract
      -> text as String
      <- score as Integer?

    LengthScorer is Scorer as pure
      -> text as String
      <- score as Integer: length text

    UpperScorer is Scorer as pure
      -> text as String
      <- score as Integer: length text.upperCase()

    //Non-pure abstract: implementations can be impure
    Reporter as abstract
      -> message as String
      <- report as String?

    SimpleReporter is Reporter
      -> message as String
      <- report as String: "[REPORT] " + message

  defines program

    PureAbstractFunctionDemo()
      stdout <- Stdout()

      //Pure function hierarchy
      scorers <- List() of Scorer
      scorers += LengthScorer
      scorers += UpperScorer

      for scorer in scorers
        stdout.println(`Score: ${scorer("Hello World")}`)

      //Non-pure function hierarchy
      reporter <- SimpleReporter
      stdout.println(reporter("system ready"))

Java: no purity on functional interfaces. Kotlin: no purity on function types. Rust: Fn traits have no purity annotation. EK9: pure abstract functions enforce purity on all implementations via E05150.

E05150 abstract contract extend extension function immutable implementation pure purity side-effect

LengthScorer is Scorer
      -> text as String
      <- score as Integer: length text

Explanation: When the abstract function is declared as pure, every implementation must also be pure. Omitting 'as pure' violates the purity contract. See ek9 -h E05150 for details.

UpperScorer is Scorer as pure
      -> text as String
      <- score as Integer: length text.upperCase()
      stdout.println(score)

Explanation: A pure function cannot call non-pure methods like stdout.println(). The purity contract inherited from the abstract function forbids side effects. See ek9 -h E50001 for details.


Question: What is the difference between a function and a method in EK9?

How do functions differ from methods in EK9?

When should I use a function instead of a method in EK9?

Are functions and methods interchangeable in EK9?

Answer:
Functions and methods in EK9 are fundamentally different constructs. Functions are stateless first-class types defined at module level. Methods are bound to the state of a class, trait, or record.

FUNCTIONS ARE TYPES
Functions in EK9 are declared in a 'defines function' block at module level. Every function is a nominal type with its own identity. Functions can be stored in variables, passed as arguments, returned from other functions, and collected in lists. Functions do NOT have access to any class state because they exist outside of any class.

METHODS ARE BOUND TO STATE
Methods are declared inside a class, trait, or record. They have access to the properties of their enclosing type via 'this'. Methods can have visibility modifiers (public, protected, private). Methods can be overridden in subclasses. Methods cannot be stored in variables independently of their object.

SYNTAX COMPARISON
Both use '->' for parameters and '<-' for returns. Both can be marked 'as pure'. The syntax is deliberately similar so developers focus on the conceptual difference (stateless vs stateful) rather than syntactic differences.

FUNCTION ADVANTAGES
Functions are testable in isolation (no object setup needed). Functions compose naturally (pass one function to another). Functions enable polymorphism without classes (via abstract function types). Functions enforce statelessness, which aids reasoning and parallelism.

METHOD ADVANTAGES
Methods encapsulate state. Methods support inheritance hierarchies. Methods support dispatching on the receiver type. Methods enable the standard OOP patterns (encapsulation, polymorphism via classes).

WHEN TO CHOOSE
Use functions for pure computations, transformations, and pipeline stages. Use methods when behaviour is intrinsically tied to object state. Use abstract functions when you need callable polymorphism without classes.

See Q49 for function basics. See Q93 for class and method basics. See Q105 for method dispatch in classes. See Q255 for cost-based method resolution. See Q597 for function parameter patterns. See Q600 for method overloading vs function dispatching.

defines module qa.functionsAndMethods.functionVsMethod

  defines function

    //Function: stateless, at module level, first-class type
    formatName() as pure
      ->
        first as String
        last as String
      <- result as String: `${last}, ${first}`

    //Abstract function: defines a callable contract
    Transformer as pure abstract
      -> input as String
      <- output as String?

    //Named function implementing abstract type
    UpperTransformer is Transformer as pure
      -> input as String
      <- output as String: input.upperCase()

  defines class

    //Class with methods: methods access 'this' state
    Greeter
      prefix <- String()

      Greeter()
        -> prefix as String
        this.prefix: prefix

      //Method: accesses class state (prefix)
      greet()
        -> name as String
        <- message as String: `${prefix} ${name}`

      default operator ?

  defines program

    FunctionVsMethodDemo()
      stdout <- Stdout()

      // === FUNCTION: stateless, no object needed ===
      stdout.println(formatName("Steve", "Limb"))

      // === METHOD: requires object with state ===
      greeter <- Greeter("Hello")
      stdout.println(greeter.greet("World"))

      // === FUNCTION AS TYPE: store in variable ===
      transformer as Transformer: UpperTransformer
      stdout.println(transformer("hello world"))

      // === FUNCTIONS IN LISTS: polymorphic iteration ===
      lower <- () is Transformer as pure (output:=? input.lowerCase())
      transformers <- [UpperTransformer, lower]
      for item in transformers
        stdout.println(item("Mixed Case"))

Java: all functions must live inside classes as static methods or instance methods, no standalone functions, functional interfaces (SAM) are a workaround. Python: def creates functions at module level or methods inside classes, no formal distinction in type system. JavaScript: functions are standalone, methods are properties of objects, 'this' binding is confusing. Rust: fn defines standalone functions, impl blocks add methods to structs, methods take &self. Go: functions are standalone, methods use receiver syntax, no inheritance. Kotlin: top-level functions exist alongside class methods, extension functions blur the line. Swift: free functions and methods, protocol methods. EK9: functions are first-class nominal types at module level, methods are bound to class/trait/record state, both use identical syntax, functions can form type hierarchies via abstract.

bound class difference first-class function method module parameter state stateful stateless type

Explanation: When a class inherits operator ? from a base type, the implementation must use the 'override' keyword (or 'default' for auto-generated). Declaring bare 'operator ?' triggers E07520 because operator semantics require a Boolean return. See ek9 -h E07520 for details.

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


Question: How do function parameters work in EK9?

What are the parameter passing rules in EK9?

How do I declare function parameters in EK9?

What is the difference between inline and block parameters?

Answer:
EK9 function parameters use '->' for inputs and '<-' for the named return value. Parameters can be declared inline (single parameter) or in block style (multiple parameters).

SINGLE PARAMETER INLINE
For a single parameter, declare it directly after '->':
  greet()
    -> name as String
    <- message as String: "Hello, " + name

MULTIPLE PARAMETERS BLOCK STYLE
Multiple parameters are indented under '->':
  add() as pure
    ->
      a as Integer
      b as Integer
    <- result as Integer: a + b

RETURN VALUE
The return is declared with '<-' and a named variable. The compiler ensures all code paths initialise this variable. There is NO return statement in EK9.

SANITIZED PARAMETERS
The 'sanitized' keyword marks parameters that come from untrusted sources. The compiler copies the value through a sanitizing constructor:
  processInput()
    -> userInput as sanitized String
    <- cleaned as String: userInput.trim()
This prevents injection attacks at the language level.

ALL PARAMETERS MUST BE USED
The compiler errors (E08091) if a parameter is unused. Unused parameters are dead code: they increase signature complexity without contributing to the result. Abstract methods, overrides, and dispatchers are exempt from this check.

PARAMETER PASSING SEMANTICS
EK9 passes parameters by value for primitives and by reference for objects. Parameters are read-only by default in pure functions.

See Q49 for function basics. See Q54 for pure functions and Consumer vs Acceptor. See Q215 for sanitized parameters in depth. See Q319 for unused parameter detection. See Q596 for function vs method distinction. See Q598 for why EK9 has no default parameters. See Q599 for why EK9 has no varargs.

defines module qa.functionsAndMethods.parameters

  defines function

    //Single parameter inline
    greet() as pure
      -> name as String
      <- message as String: `Hello, ${name}`

    //Multiple parameters block style
    add() as pure
      ->
        a as Integer
        b as Integer
      <- result as Integer: a + b

    //Return with body computation
    clampValue() as pure
      ->
        number as Integer
        minVal as Integer
        maxVal as Integer
      <- result as Integer: number
      if number < minVal
        result: minVal
      else if number > maxVal
        result: maxVal

    //Sanitized parameter for untrusted input
    cleanInput() as pure
      -> userInput as sanitized String
      <- cleaned as String: userInput.trim()

  defines program

    ParameterDemo()
      stdout <- Stdout()

      // === SINGLE PARAMETER ===
      stdout.println(greet("World"))

      // === MULTIPLE PARAMETERS ===
      stdout.println(`add(3, 4): ${add(3, 4)}`)

      // === RETURN WITH BODY ===
      stdout.println(`clamp(15, 0, 10): ${clampValue(15, 0, 10)}`)
      stdout.println(`clamp(-5, 0, 10): ${clampValue(-5, 0, 10)}`)
      stdout.println(`clamp(7, 0, 10): ${clampValue(7, 0, 10)}`)

      // === SANITIZED PARAMETER ===
      stdout.println(cleanInput("  trimmed  "))

Java: parameters declared in parentheses, types before names, no named returns, return statement required, no sanitization keyword, unused parameters not flagged. Python: def func(a, b): with dynamic typing, *args and **kwargs for variable arguments, default values, no compile-time unused check. JavaScript: function(a, b) with no type safety, arguments object, rest parameters, no compile-time checks. Rust: fn func(a: i32, b: i32) -> i32, explicit return type, return keyword used, no sanitization. Go: func add(a, b int) int, explicit return type, return keyword. Kotlin: fun add(a: Int, b: Int): Int, default parameter values supported. EK9: '->' for parameters, '<-' for named return, no return statement, sanitized keyword for security, unused parameters are compile errors, block style for multiple parameters.

argument block function immutable inline input method migrate output parameter pure return sanitized side-effect style unused

if number < minVal
        return minVal
      else if number > maxVal
        return maxVal
      return number

Explanation: EK9 has no return statement. Declare the return variable with a default and use if/else to modify it. See ek9 -h E01072 for details.


Question: Why doesn't EK9 have default parameter values?

Can I set default values for function parameters in EK9?

How do I handle optional parameters without defaults in EK9?

What replaces default parameter values in EK9?

Answer:
EK9 deliberately excludes default parameter values. This is a designed exclusion based on the problems defaults create in production code.

WHY DEFAULTS WERE REMOVED
Default parameter values cause three categories of bugs. First, they hide complexity at call sites: callers cannot tell which defaults are being used without reading the function signature. Second, they create fragile APIs: changing a default value silently changes behaviour for all callers. Third, they complicate overload resolution: when combined with method overloading, defaults create ambiguous call resolution that even compiler writers find difficult to specify correctly.

THE EVIDENCE
C++ default parameters combined with virtual methods create inheritance bugs (base vs derived defaults). Python mutable default arguments (def f(x=[])') are a well-known trap. Kotlin and Scala defaults with overloading create ambiguous resolution requiring explicit disambiguation.

EK9 ALTERNATIVES
Constructor overloading provides the same convenience for classes:
  Config()
    -> maxRetries as Integer
    this(maxRetries, 30)
  Config()
    -> maxRetries as Integer, timeoutSeconds as Integer
    this.maxRetries: maxRetries
    this.timeoutSeconds: timeoutSeconds

Function delegation chains one function to another with explicit values:
  connectSimple()
    -> host as String
    <- rtn as String: connectFull(host, 8080)

Every call site is explicit. Every value is visible. No hidden assumptions.

See Q49 for function basics. See Q94 for constructor overloading. See Q118 for builder pattern as alternative for many optional values. See Q580 for constructor delegation patterns. See Q597 for parameter syntax.

defines module qa.functionsAndMethods.noDefaults

  defines class

    //Constructor overloading replaces default parameters
    Config
      maxRetries <- 0
      timeoutSeconds <- 0

      Config()
        -> maxRetries as Integer
        this(maxRetries, 30)

      Config()
        ->
          maxRetries as Integer
          timeoutSeconds as Integer
        this.maxRetries: maxRetries
        this.timeoutSeconds: timeoutSeconds

      describe() as pure
        <- rtn as String: `retries=${maxRetries}, timeout=${timeoutSeconds}`

      default operator ?

  defines function

    //Function delegation: wraps another function with explicit values
    connectSimple() as pure
      -> host as String
      <- rtn as String: connectFull(host, 8080)

    connectFull() as pure
      ->
        host as String
        port as Integer
      <- rtn as String: `${host}:${port}`

  defines program

    NoDefaultParamsDemo()
      stdout <- Stdout()

      // === CONSTRUCTOR OVERLOADING (replaces default params) ===
      simple <- Config(3)
      stdout.println(`Simple: ${simple.describe()}`)

      full <- Config(5, 60)
      stdout.println(`Full: ${full.describe()}`)

      // === FUNCTION DELEGATION (replaces default params) ===
      stdout.println(connectSimple("localhost"))
      stdout.println(connectFull("localhost", 9090))

Java: no default parameters, method overloading used instead, builder pattern for many options. Python: def func(x, timeout=30) supports defaults, mutable default bug is well-known, overuse leads to functions with 10+ parameters. JavaScript: function(x, timeout = 30) with ES6 defaults, no type safety. Rust: no default parameters, builder pattern or Option types used instead. Go: no default parameters, functional options pattern (variadic WithXxx functions). Kotlin: fun connect(host: String, port: Int = 8080) with named defaults, can conflict with overloading. C#: optional parameters with default values, can break binary compatibility. Swift: func connect(host: String, port: Int = 8080) with defaults, named parameters help readability. EK9: no default parameters by design, use constructor overloading or function delegation, every value explicit at call site.

absent complexity constructor default delegation explicit function guard hidden method migrate optional overload parameter safe value

Config()
        -> maxRetries as Integer
        maxRetries: maxRetries + 1
        this(maxRetries, 30)

Explanation: The this() delegation call must be the very first statement in the constructor body. No code can execute before delegation. See ek9 -h E08110 for details.


Question: Why doesn't EK9 have variable arguments (varargs)?

Can I pass a variable number of arguments to a function in EK9?

How do I handle unknown numbers of parameters in EK9?

Answer:
EK9 deliberately excludes variable arguments (varargs). This is a designed exclusion based on the problems varargs create.

WHY VARARGS WERE REMOVED
Variable arguments lose type safety at boundaries. In Java, 'printf(String, Object...)' accepts anything, and type errors become runtime exceptions. Varargs hide the actual parameter count from complexity metrics, allowing functions to accept unbounded input while appearing simple. They also make APIs ambiguous when combined with overloading.

THE EVIDENCE
Java varargs with generics produce heap pollution warnings. C printf-style varargs are a major source of security vulnerabilities (format string attacks). Python *args encourages functions that accept everything and validate nothing.

EK9 ALTERNATIVE: PASS A LIST
Instead of varargs, pass a typed List explicitly:
  sumAll()
    -> numbers as List of Integer
    <- total as Integer: 0
    for number in numbers
      total += number

Call with a list literal:
  result <- sumAll([1, 2, 3, 4, 5])

This approach is typed (the compiler knows the element type), bounded (the list has a known length at the call site), and self-documenting (the parameter name describes the collection).

STREAM ALTERNATIVE
For transforming variable-length data, use stream pipelines:
  items <- ["hello", "world", "foo"]
  cat items > stdout
Pipelines handle collections of any size naturally.

See Q49 for function basics. See Q45 for List type. See Q597 for parameter syntax. See Q598 for why default parameters are also excluded.

defines module qa.functionsAndMethods.noVarargs

  defines function

    //Instead of varargs: accept a typed List
    sumAll()
      -> numbers as List of Integer
      <- total as Integer: 0
      for number in numbers
        total += number

    //Another typed list alternative
    joinAll()
      ->
        items as List of String
        separator as String
      <- result as String: String()
      first <- true
      for item in items
        if first
          result: item
          first: false
        else
          result: `${result}${separator}${item}`

  defines program

    NoVarargsDemo()
      stdout <- Stdout()

      // === PASS A LIST INSTEAD OF VARARGS ===
      total <- sumAll([1, 2, 3, 4, 5])
      stdout.println(`Sum: ${total}`)

      total2 <- sumAll([10, 20])
      stdout.println(`Sum2: ${total2}`)

      // === JOIN WITH SEPARATOR ===
      joined <- joinAll(["hello", "world", "foo"], ", ")
      stdout.println(`Joined: ${joined}`)

      // === LIST LITERAL IS CONCISE ===
      stdout.println(`Empty sum: ${sumAll(List() of Integer)}`)

      // === STREAM PIPELINE FOR VARIABLE DATA ===
      items <- ["alpha", "beta", "gamma"]
      cat items > stdout

Java: varargs with Object... or specific type, heap pollution with generics, autoboxing complications. Python: *args and **kwargs accept anything, no compile-time type checking. JavaScript: rest parameters (...args) with no type safety, arguments object legacy. Rust: no varargs, macros (println!) handle variable arguments at compile time. Go: variadic functions with ...Type, type-safe but only for last parameter. C: va_list varargs are type-unsafe, source of format string vulnerabilities. Kotlin: vararg keyword, similar to Java. Swift: variadic parameters with Type..., type-safe. EK9: no varargs by design, pass List of T explicitly, typed and bounded, stream pipelines for variable-length processing.

arguments bounded collection function list method migrate parameter printf stream typed varargs variable

Explanation: Integer has no toString() method in EK9; use the '$' prefix operator or string interpolation instead. See ek9 -h E50060 for details.

joined <- joinAll(["hello", "world", "foo"], ", ").toUpperCase()