How do I work with measurements and units in EK9?

← Getting Started · Ref: Q36

Dimension is EK9's built-in type for unit-aware measurements. Any number followed by a unit suffix becomes a literal: 1cm, 10px, 4.5em, 8mile. The unit suffix is freeform.

Same-unit arithmetic works normally. Different-unit operations return unset (safety against unit mismatch). Scaling by number preserves the unit. Dimension/Dimension of same unit gives a Float ratio. Convert units with convert(): eightMiles.convert(1.609344km).

Operators: +, -, *, /, ^, abs, sqrt, comparison, <?. Use #< to extract numeric value.

Use 'ek9 -h Dimension' to see the full API.

See Q35 for Money. See Q39 for Integer/Float. See Q44 for locale formatting.

Example

defines module qa.dimension

  defines program
    DimensionDemo()
      stdout <- Stdout()

      // === DIMENSION LITERALS ===

      // Format: number followed by unit suffix (any string)
      oneCentimetre <- 1cm
      tenPixels <- 10px
      fourAndHalfEm <- 4.5em
      oneAndHalfEm <- 1.5em
      eightMiles <- 8mile
      stdout.println(`cm: ${oneCentimetre}, px: ${tenPixels}, em: ${fourAndHalfEm}`)

      // Unset dimension
      unsetDim <- Dimension()
      require ~unsetDim?

      // === ARITHMETIC: SCALING BY NUMBER ===

      // Multiply dimension by number — scales the amount, keeps the unit
      doubled <- oneCentimetre * 2
      require doubled == 2cm
      stdout.println(`1cm * 2 = ${doubled}`)

      // Divide dimension by number — scales down
      divided <- tenPixels / 5
      require divided == 2px
      stdout.println(`10px / 5 = ${divided}`)

      // Add a plain number to a dimension
      wider <- fourAndHalfEm + 0.6
      require wider == 5.1em
      stdout.println(`4.5em + 0.6 = ${wider}`)

      // === ARITHMETIC: SAME-UNIT ADDITION ===

      // Add dimensions with the SAME unit
      combined <- fourAndHalfEm + oneAndHalfEm
      require combined == 6em
      stdout.println(`4.5em + 1.5em = ${combined}`)

      // === ARITHMETIC: DIMENSION / DIMENSION GIVES A NUMBER ===

      // Dividing dimension by dimension of same unit gives a unitless Float
      ratio <- fourAndHalfEm / oneAndHalfEm
      require ratio == 3
      stdout.println(`4.5em / 1.5em = ${ratio} (unitless)`)

      // === SAFETY: DIFFERENT UNITS RETURN UNSET ===

      // Cannot add centimetres to pixels — different units
      invalidAdd <- oneCentimetre + tenPixels
      require ~invalidAdd?
      stdout.println(`cm + px isSet: ${invalidAdd?}`)

      // Comparison across different units also returns unset
      invalidCompare <- oneCentimetre <> tenPixels
      require ~invalidCompare?

      // === UNIT CONVERSION ===

      // Define a conversion factor: 1 mile = 1.609344 km
      numberOfKmInMiles <- 1.609344km
      inKM <- eightMiles.convert(numberOfKmInMiles)
      require inKM == 12.874752km
      stdout.println(`${eightMiles} in km is ${inKM}`)

      // But after conversion, original and converted have DIFFERENT units
      // So adding them returns unset — must pick one unit system
      stillInvalid <- eightMiles + inKM
      require ~stillInvalid?

      // === EXTRACT NUMERIC VALUE ===

      // The #< operator extracts the number without the unit
      numericValue <- #< inKM
      require numericValue == 12.874752
      stdout.println(`Numeric value without unit: ${numericValue}`)

      // === UNARY OPERATORS ===

      // Negation
      returnJourney <- -eightMiles
      stdout.println(`Return journey: ${returnJourney}`)

      // Absolute value
      require abs returnJourney == eightMiles

      // Square root
      sqrtEm <- sqrt combined
      stdout.println(`sqrt 6em = ${sqrtEm}`)

      // Power
      squared <- inKM ^ 2
      stdout.println(`Squared: ${squared}`)

      // === COMPOUND ASSIGNMENT AND INCREMENT ===

      working <- 5.1em
      working += 0.9
      require working == 6em
      stdout.println(`After +=: ${working}`)

      working++
      require working == 7em
      stdout.println(`After ++: ${working}`)

      // === COMPARISON ===

      require fourAndHalfEm < combined
      require combined > fourAndHalfEm
      require fourAndHalfEm <> combined
      require fourAndHalfEm <= 4.5em
      require fourAndHalfEm >= 4.5em

      // Min operator
      lesser <- fourAndHalfEm <? combined
      require lesser == fourAndHalfEm
      stdout.println(`Min of 4.5em and 6em: ${lesser}`)

Common mistakes

E50060 — EK9 Dimension does not have a getValue() method. Use operators for arithmetic and the $ operator for string representation. Triggers E50060 — method not resolved. See ek9 -h Dimension for the full API.

Incorrect:

eightMiles.convertTo(numberOfKmInMiles)

Correct:

eightMiles.convert(numberOfKmInMiles)
Other ways to ask this
  • Does EK9 have a built-in unit type for measurements?
  • How does EK9 prevent unit mismatch errors?
  • How do I convert between units like miles and kilometres in EK9?
  • What is the Dimension type in EK9?

Coming from another language?

Java: plain double, manual unit tracking. F#: compile-time units. CSS: declarative only. EK9: freeform unit literals, unit-safe arithmetic returns unset for mismatches, convert() for boundaries.

Keywords: metre, kilometre, intro, pixel, scaling, dimension, unit, css, start, measurement, orbiter, mars, mile, convert, beginner, first