How does indentation work in EK9?

← Getting Started · Ref: Q16

EK9 uses significant indentation to define scope, similar to Python. There are no braces, no semicolons, and no end keywords.

The rules are strict and enforced by the lexer:

1. Exactly 2 spaces per indentation level

   Level 0: no indent (module declaration)
   Level 1: 2 spaces (construct blocks like defines function)
   Level 2: 4 spaces (function names, class names)
   Level 3: 6 spaces (function body)
   And so on.

2. Tabs are NOT allowed

   The lexer rejects tabs with: "Tabs not supported for indentation; use spaces"
   Configure your editor to insert spaces when you press Tab.

3. Odd numbers of spaces are NOT allowed

   The lexer rejects odd space counts with: "Odd number of spaces for indentation"
   Indentation must always be a multiple of 2. A line indented by 3 or 5 spaces is an error.

4. Indentation must increase by exactly one level

   You cannot jump from level 1 (2 spaces) to level 3 (6 spaces).
   Each nested block increases by exactly 2 spaces.

5. Dedenting can drop multiple levels at once

   Returning from deeply nested code can decrease by several levels in one step.

The compiler generates synthetic INDENT and DEDENT tokens from the whitespace, similar to how Python's lexer works. This means the parser never sees raw spaces: it sees structured block markers.

Editor setup:
- Set tab key to insert 2 spaces (not a tab character)
- Enable "show whitespace" to catch mixed indentation
- The EK9 VSCode extension handles this automatically
- In the REPL, pressing Tab inserts 2 spaces

The code example below shows correct indentation at multiple nesting levels.

See Q5 for source file structure. See Q49 for function definitions that demonstrate indentation levels. See Q622 for automatic code formatting.

Example

defines module qa.getting.started.indentation

  defines function

    outerFunction()
      -> innerValue as Integer
      <- rtn as String: String()

      if innerValue > 0
        rtn: "positive: " + $innerValue
      else
        rtn: "non-positive"

  defines class

    IndentExample
      name as String: "default"

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

      describe()
        <- rtn as String: `IndentExample(${name})`

      default operator ?

  defines program
    Indentation()
      stdout <- Stdout()

      example <- IndentExample("two spaces per level")
      stdout.println(example.describe())
      stdout.println(outerFunction(42))

Common mistakes

E08180 — Class fields must be initialised inline. An uninitialised field triggers E08180. Provide a default value using a colon and literal or constructor call. See ek9 -h E08180 for details.

Incorrect:

name as String

Correct:

name as String: "default"

E07520 — The ? operator is inherited from the base type. Use 'default operator ?' to auto-generate it, or 'override operator ?' to provide a custom implementation. Declaring bare 'operator ?' triggers E07520 because operator semantics require a Boolean return. See ek9 -h E07520 for details.

Incorrect:

operator ?

Correct:

default operator ?
Other ways to ask this
  • Does EK9 use braces or indentation?
  • How many spaces per indent level in EK9?
  • Can I use tabs in EK9?
  • Why does EK9 reject odd numbers of spaces?
  • How is EK9 indentation like Python?

Coming from another language?

Python: also uses significant indentation but allows 4 spaces (PEP 8) or any consistent count. Java/C/Rust/Go: use braces for scope. Ruby: uses end keywords. Haskell: uses layout rules similar to EK9. EK9 is stricter than Python: exactly 2 spaces, no tabs, no odd counts.

Keywords: first, dedent, whitespace, braces, indentation, tabs, nesting, scope, beginner, level, indent, spaces, start, migrate, intro