How are EK9 source files structured?
← Getting Started · Ref: Q5
Every EK9 source file follows this structure:
1. Shebang line: #!ek9 (required first line, enables direct execution on Unix)
2. Optional comment header between doc comment markers
3. Module declaration: `defines module <dotted.name>`
4. Optional `references` block (imports from other modules)
5. One or more construct blocks inside the module
Idiomatic ordering of construct blocks (top to bottom):
defines type type aliases and constrained types defines constant named constant values defines record data-only types (fields, constructors, operators) defines trait interfaces for polymorphism defines class full object types with methods and operators defines function standalone functions defines component dependency-injected types defines text internationalized text templates defines service web service endpoints defines application wires components together defines program executable entry points (always last)
Within aggregates (classes, records, traits) the ordering is enforced by the grammar:
1. Properties/fields 2. Constructors and methods 3. Operators 4. default operator (generates synthetic operators like ==, <>, $, #?)
Style guidelines:
- Use only ONE `defines <construct>` block per type per file (avoid scattered blocks)
- Multiple files CAN share the same module name, splitting a module across files by concern
- Directory structure is your choice (unlike Java, the module name does not dictate the path)
One module per file. The module name is the namespace for everything defined in it.
For module organization, run: ek9 -q organize code modules
See Q6 for organizing code into modules. See Q16 for indentation rules. See Q17 for entry points with defines program. See Q18 for comment styles. See Q20 for file extension.
Example
defines module qa.getting.started.source.file.structure defines constant Greeting <- "Hello from EK9" defines function decorateMessage() as pure -> message as String <- result as String: `[${message}]` defines record Person name as String: String() Person() -> n as String name :=: n default operator ? operator $ as pure <- rtn as String: name defines program ShowStructure() stdout <- Stdout() person <- Person("Steve") decorated <- decorateMessage($person) stdout.println(Greeting) stdout.println(decorated)
Common mistakes
E08180 — Class and record fields must be initialised inline. Leaving a field uninitialised produces E08180. Use an explicit constructor call or literal value. See ek9 -h E08180 for details.
Incorrect:
name as String
Correct:
name as String: String()
E07520 — The ? operator is inherited from the base and must use 'override' or be generated with 'default'. Declaring 'operator ?' without 'default' or 'override' triggers E07520 because the bare declaration lacks proper return semantics. See ek9 -h E07520 for details.
Incorrect:
operator ?
Correct:
default operator ?
E01030 — Defining a function with the same name as a record in the same module creates a name collision between different symbol kinds. Triggers E01030 — variable/function/type duplicated. Each name must be unique within its module. See ek9 -h E01030 for details.
Incorrect:
Person() as pure -> message as String <- result as String: `[${message}]`
Correct:
decorateMessage() as pure -> message as String <- result as String: `[${message}]`
Other ways to ask this
- What is the structure of an EK9 file?
- How do I organize an EK9 source file?
- What sections does an EK9 file have?
Coming from another language?
Python: modules with imports and classes/functions at top level. Java: one public class per file with package declaration and directory must match package name. Rust: mod/crate system with use statements. Go: package declaration with func/type/var. Unlike Java, EK9 does not require directory structure to match module names.
Keywords: construct, section, first, source, defines, module, beginner, file, structure, layout, organize, start, ordering, migrate, intro