What EK9 constructs are available and when should I use each?
← Classes and OOP · Ref: Q119
EK9 provides a rich set of constructs, each designed for specific purposes. Choosing the right construct leads to clearer, more maintainable code.
CONSTRUCT OVERVIEW
Class: Encapsulated behaviour, private properties, methods, constructors.
Record: Transparent data, public properties, ideal for DTOs and values.
Trait: Behaviour contracts, no mutable state, multiple implementation.
Component: DI-managed services, injection with '!', application registration.
Enumeration: Named constant values, auto-generated operators, iteration.
Text: Internationalized strings, locale-specific, compiler-validated.
Service: REST/HTTP endpoints, operator-to-HTTP mapping, URI binding.
Function: Standalone callable units, pure functions, higher-order.
Program: Entry points with optional application binding.
Application: DI container, component and service registration.
Type: Constrained types derived from built-in types.
Constant: Module-level immutable values.
DECISION GUIDE
Need behaviour with hidden state? Class.
Need transparent data? Record.
Need shared behaviour contract? Trait.
Need injectable service? Component.
Need fixed set of values? Enumeration.
Need localised text? Text.
Need HTTP endpoint? Service.
PHILOSOPHY
EK9 favours composition over inheritance (closed by default), behaviour through traits, and explicit DI through components. Each construct has a single clear purpose.
See Q93 for classes. See Q97 for records. See Q99 for enumerations. See Q106 for traits. See Q111 for components. See Q49 for functions. See Q17 for entry points. See Q1 for minimal program.
Example
defines module qa.oop.overview defines type Rating Low Medium High defines record Item name <- String() rating <- Rating() Item() -> name as String rating as Rating this.name: name this.rating: rating default operator defines function describeItem() as pure -> item as Item <- rtn as String: `${item.name} [${item.rating}]` defines class Catalog items <- List() of Item add() -> item as Item items += item count() as pure <- rtn as Integer: length items listAll() <- rtn as List of Item: items default operator ? defines program OverviewDemo() stdout <- Stdout() // === ENUMERATION === priority <- Rating.High stdout.println(`Rating: ${priority}`) // === RECORD === item <- Item("Widget", Rating.Medium) stdout.println(`Item: ${item}`) // === FUNCTION === stdout.println(describeItem(item)) // === CLASS === catalog <- Catalog() catalog.add(Item("Gadget", Rating.High)) catalog.add(Item("Tool", Rating.Low)) catalog.add(item) stdout.println(`Catalog size: ${catalog.count()}`) for entry in catalog.listAll() stdout.println(` ${describeItem(entry)}`)
Common mistakes
E06180 — Record fields like 'item.name' are public, but class fields like 'catalog.items' are private. Accessing a private class field from outside triggers E06180. Use the class's public methods instead. See ek9 -h E06180 for details.
Incorrect:
stdout.println(`Catalog size: ${catalog.items}`)
Correct:
stdout.println(`Catalog size: ${catalog.count()}`)
E50060 — Item is a record — it has no 'describe' method. In EK9, behaviour belongs in standalone functions, not on records. Calling a non-existent method triggers E50060. Use describeItem(item) instead. See ek9 -h E50060 for details.
Incorrect:
item.describe()
Correct:
describeItem(item)
E07290 — Records can only have constructors and operators — not named methods. Defining 'describe()' on Item triggers E07290. Use a standalone function like describeItem() instead. See ek9 -h E07290 for details.
Incorrect:
describe()
<- rtn as String: name
Correct:
default operator
E50060 — EK9 does not have toString(). Use the $ operator or string interpolation — the record's 'default operator' auto-generates $ for string conversion. See ek9 -h E50060 for details.
Incorrect:
stdout.println(item.toString())
Correct:
stdout.println(`Item: ${item}`)
E50001 — EK9 enumeration values are case-sensitive. 'HIGH' does not match the defined value 'High'. Check the exact casing of enumeration values. See ek9 -h E50001 for details.
Incorrect:
priority <- Rating.HIGH
Correct:
priority <- Rating.High
Other ways to ask this
- What are all the construct types in EK9?
- How do I choose between class record trait and component?
- What is the complete list of EK9 type constructs?
Coming from another language?
Java: class, interface, enum, record (Java 16), annotation, no built-in component/service/text constructs. Python: class, no enum until 3.4, no built-in DI or service constructs. Rust: struct, enum, trait, impl, no class or component concepts. Go: struct, interface, no class, enum, component, or service constructs. Kotlin: class, data class, interface, enum class, object, no built-in DI or service. EK9: twelve distinct constructs each with clear purpose - class, record, trait, component, enumeration, text, service, function, program, application, type, constant.
Keywords: construct, function, service, trait, constant, oop, text, overview, object-oriented, application, component, class, record, program, enumeration