How do I define a function in EK9?

← Getting Started · Ref: Q49

EK9 functions are fundamentally different from functions in other languages because they are first-class TYPES, not just callable code blocks. Every function in EK9 is a nominal type with identity, and functions can participate in type hierarchies via 'is' and 'extends'. This makes them far more powerful than functions in Java, Python, Go, or even Rust.

Functions are defined inside a 'defines function' block within a module. Parameters use '->' for inputs and '<-' for the named return value:

  greet()
    -> name as String
    <- message as String: "Hello, " + name

Multiple parameters use block style (indented under '->'):

  add() as pure
    ->
      a as Integer
      b as Integer
    <- result as Integer: a + b

There is NO return statement in EK9. Instead, you declare a named return variable with '<-'. The compiler ensures all code paths initialise that variable. If you provide a default value (': a + b'), the function body is optional. See Q50 for the full power of named returns.

When computation requires multiple steps, add a body after the return declaration:

  clamp() as pure
    ->
      number as Integer
      min as Integer
      max as Integer
    <- result as Integer: number
    if number < min
      result: min
    else if number > max
      result: max

Because functions are types, they can be stored in variables, passed as parameters, returned from other functions, and collected in Lists. This enables patterns that require interfaces or abstract classes in other languages. See Q51 for abstract functions, Q52 for dynamic functions, Q54 for pure functions and the Consumer/Acceptor distinction, Q55 for delegates, and Q56 for higher-order functions.

EK9 also enforces quality limits on ALL functions at compile time: cyclomatic complexity must be less than 11, nesting depth less than 4, statement count less than 20, and variable names must be descriptive. These limits cannot be disabled and apply equally to all function types.

See Q93 for defining classes. See Q106 for traits. See Q256 for the Void type when functions return nothing. See Q294 for function naming conventions.

Use 'ek9 -h function' to see the full syntax reference. See Q319 for unused parameter detection. See Q588 for function extension and type hierarchies. See Q596 for function vs method distinction. See Q597 for function parameter patterns in depth.

Example

defines module qa.function

  defines function

    greet() as pure
      -> name as String
      <- message as String: "Hello, " + name

    add() as pure
      ->
        a as Integer
        b as Integer
      <- result as Integer: a + b

    clamp() as pure
      ->
        number as Integer
        min as Integer
        max as Integer
      <- result as Integer: number
      if number < min
        result: min
      else if number > max
        result: max

    factorial() as pure
      -> n as Integer
      <- result as Integer: 1
      for i in 1 ... n
        result: result * i

  defines program

    FunctionDemo()
      stdout <- Stdout()

      // Single-parameter function call
      stdout.println(greet("World"))

      // Multi-parameter function call
      stdout.println(`add(3, 4): ${add(3, 4)}`)

      // Function with body logic
      stdout.println(`clamp(15, 0, 10): ${clamp(15, 0, 10)}`)
      stdout.println(`clamp(-5, 0, 10): ${clamp(-5, 0, 10)}`)
      stdout.println(`clamp(7, 0, 10): ${clamp(7, 0, 10)}`)

      // Pure function
      stdout.println(`factorial(5): ${factorial(5)}`)

Common mistakes

E06270 — The function 'add' takes exactly two Integer parameters. Passing three arguments triggers E06270 — parameter mismatch. EK9 does not support varargs or default parameters. See ek9 -h E06270 for details.

Incorrect:

${add(3, 4, 5)}

Correct:

${add(3, 4)}

E50001 — A typo in the function name 'gret' means the compiler cannot find any identifier with that name. EK9 is case-sensitive and requires exact spelling. See ek9 -h E50001 for details.

Incorrect:

stdout.println(gret("World"))

Correct:

stdout.println(greet("World"))

E01030 — EK9 does not support function overloading. Defining two functions with the same name but different parameters triggers E01030. Use distinct names like 'add2' and 'add3', or use a single function with a List parameter. See ek9 -h E01030 for details.

Incorrect:

add() as pure
      ->
        a as Integer
        b as Integer
      <- result as Integer: a + b

    add() as pure
      ->
        a as Integer
        b as Integer
        c as Integer
      <- result as Integer: a + b + c

Correct:

add() as pure
      ->
        a as Integer
        b as Integer
      <- result as Integer: a + b

E01072 — EK9 does not have a 'return' statement. Declare the return variable with '<-' and the compiler ensures all code paths initialise it. See ek9 -h E01072 for details.

Incorrect:

<- result as Integer: number
      return result

Correct:

<- result as Integer: number
Other ways to ask this
  • What is a function in EK9?
  • How do EK9 functions differ from functions in other languages?
  • How do I create a named function in EK9?

Coming from another language?

Java: methods live inside classes, no standalone functions, static methods are a workaround, functional interfaces require SAM conversion, no compile-time quality enforcement. Python: def creates functions but they have no type contract, no compile-time parameter type checking, no quality enforcement. JavaScript: function declarations and arrow functions have no type safety, no quality enforcement, 'this' binding is confusing. Rust: fn defines functions with strong typing but functions are not types in the OOP sense, no compile-time quality limits. Go: func defines functions, first-class values but no type hierarchies, no purity enforcement, no quality limits. C#: methods inside classes, delegates are separate concept, no quality enforcement. Kotlin: fun defines functions, similar to Java methods, no standalone function types, no quality enforcement. Swift: func defines functions, closures are structural not nominal, no quality enforcement. EK9: functions ARE types with identity and inheritance hierarchies, compile-time quality enforcement on all functions, no return statement needed, named return variables ensure all paths initialise.

Keywords: return, quality, define, beginner, function, block, intro, migrate, immutable, side-effect, parameter, start, named, complexity, pure, type, first