How do I define constants in EK9?

← Constants and Immutability · Ref: Q140

EK9 provides a dedicated 'defines constant' block at module level for declaring named constant values. Constants use the declaration operator <- with a literal value, and the type is inferred from the literal form.

DEFINES CONSTANT BLOCK

Constants are declared at module level inside a 'defines constant' block:

  defines constant
    maxRetries <- 10
    greeting <- "Hello"
    Pi <- 3.142

Each constant uses <- with a literal. No type annotation is needed because EK9 infers the type from the literal syntax.

ALL 18 CONSTANT-ELIGIBLE TYPES

Only built-in value types can be constants. EK9 supports exactly 18 types:

  Integer       42, 0xFF, 0b1010
  Float         3.14, 2.0
  Bits          0b1010 (bit manipulation)
  Boolean       true, false
  Character     'A', 'z'
  String        "Hello"
  Time          10:30, 23:59:59
  Date          2024-01-15
  DateTime      2024-01-15T10:30:00Z
  Duration      PT2H, PT30M
  Millisecond   500ms, 1000ms
  Dimension     2m, 100cm, 5.2kg
  Resolution    300dpi, 72dpi
  Colour        #FF0000, #AB6F2B
  Money         12.50#USD, 100#GBP
  RegEx         /[a-z]+/, /[S|s]te(?:ven?|phen)/
  Version       1.0.0-1, 2.3.4-0
  Path          $?.some.path

User-defined classes and records cannot be constants because copy-on-access requires compiler-known copy constructors that only built-in types guarantee.

NATIVE LITERAL SYNTAX

EK9 provides domain-specific literal syntax for many types. You write Money as 12.50#USD, Colour as #FF0000, Duration as PT2H, Dimension as 2m, and Date as 2024-01-15. These are not strings that get parsed at runtime; they are native literals that the compiler understands directly.

NAMING CONVENTIONS

EK9 does not enforce a naming convention for constants. Common styles include UPPER_CASE (like MAX_RETRIES) and camelCase (like maxRetries). Choose a convention and apply it consistently across your project.

See Q23 for the full list of built-in types. See Q31 for Date and Time details. See Q35 for Money. See Q36 for Dimension. See Q141 for how constants are protected via copy-on-access. See Q143 for how EK9 constants compare to const/final/static in other languages. See Q142 for constants across modules. See Q317 for magic literal detection and why constants should be named.

Example

defines module qa.constants.definition

  defines constant
    maxRetries <- 10
    Pi <- 3.142
    greeting <- "Hello"
    isEnabled <- true
    initial <- 'A'

    noon <- 12:00
    releaseDate <- 2024-01-15
    launchTime <- 2024-01-15T10:30:00Z
    timeout <- PT30M
    halfSecond <- 500ms

    pageWidth <- 2m
    screenDpi <- 300dpi
    brandColour <- #AB6F2B
    maxPayment <- 300000#USD
    matchSteves <- /[S|s]te(?:ven?|phen)/
    appVersion <- 1.0.0-1
    configPath <- $?.app.config

  defines program

    DefineConstantsDemo()
      stdout <- Stdout()

      // Numeric constants
      stdout.println(`Max retries: ${maxRetries}`)
      stdout.println(`Pi: ${Pi}`)

      // Text and character
      stdout.println(`Greeting: ${greeting}`)
      stdout.println(`Initial: ${initial}`)
      stdout.println(`Enabled: ${isEnabled}`)

      // Temporal constants
      stdout.println(`Noon: ${noon}`)
      stdout.println(`Release: ${releaseDate}`)
      stdout.println(`Launch: ${launchTime}`)
      stdout.println(`Timeout: ${timeout}`)
      stdout.println(`Half second: ${halfSecond}`)

      // Domain constants
      stdout.println(`Page width: ${pageWidth}`)
      stdout.println(`Screen DPI: ${screenDpi}`)
      stdout.println(`Brand colour: ${brandColour}`)
      stdout.println(`Max payment: ${maxPayment}`)
      stdout.println(`Version: ${appVersion}`)
      stdout.println(`Config: ${configPath}`)

Common mistakes

E50001 — Renaming 'maxRetries' to 'maxretries' breaks all references since EK9 is case-sensitive. The constant name must match exactly wherever it is used. See ek9 -h E50001 for details.

Incorrect:

maxretries <- 10

Correct:

maxRetries <- 10

E07890 — Constants declared in a 'defines constant' block are immutable. You cannot reassign maxRetries after declaration. Read the constant or assign it to a mutable variable instead. See ek9 -h E07890 for details.

Incorrect:

maxRetries := 20

Correct:

stdout.println(`Max retries: ${maxRetries}`)

E50001 — EK9 is case-sensitive. The constant is 'maxRetries' not 'MAX_RETRIES'. EK9 uses camelCase for all identifiers including constants. See ek9 -h E50001 for details.

Incorrect:

stdout.println(`Max retries: ${MAX_RETRIES}`)

Correct:

stdout.println(`Max retries: ${maxRetries}`)

E50060 — EK9 does not have toString(). Use string interpolation or the $ operator. See ek9 -h E50060 for details.

Incorrect:

stdout.println(Pi.toString())

Correct:

stdout.println(`Pi: ${Pi}`)
Other ways to ask this
  • How do I declare constants in EK9?
  • What types can be constants in EK9?
  • What is the defines constant block?

Coming from another language?

Java: static final fields, no dedicated constant block. Rust: const for compile-time values, limited to scalar-like types. Go: const block for basic types only (no structs/slices/maps). Kotlin: const val for primitives and String only. EK9: defines constant block supporting 18 types including Money, Colour, Dimension with native literal syntax and copy-on-access immutability.

Keywords: constant, define, immutable, inference, type, module, value, fixed, literal