How do I extract the base type value from a constrained type?
← Advanced Type System · Ref: Q718
The promote operator (#^) extracts the base type value from a constrained type, providing an explicit escape hatch for crossing type boundaries.
PROMOTE RETURNS THE BASE TYPE
The #^ operator extracts the underlying value:
rawInt <- #^ age //DrivingAge -> Integer
The result is the base type, not the constrained type. Only types whose base type defines promote (#^) support this operator.
WHICH CONSTRAINED TYPES HAVE PROMOTE
Promote is available when the base type defines it. Integer defines promote (to Float), so DrivingAge has #^. String does NOT define promote, so a String-constrained type like Name cannot use #^. Use $ (string conversion) instead for String-constrained types.
CONSTRAINED ENUMS BLOCK PROMOTE
Constrained enumerations deliberately prevent promotion back to the base enum:
redSuit <- RedCardSuit("Hearts") //Cannot do: cardSuit <- #^ redSuit //No promote to CardSuit
This is by design: constrained enums are fully disconnected types. If you could promote RedCardSuit to CardSuit, it would bypass the type boundary.
WHY PROMOTE EXISTS
Constrained types are disconnected: DrivingAge is NOT an Integer subtype. You cannot pass DrivingAge where Integer is expected. Promote is the explicit conversion:
processInteger()
-> val as Integer
//...
age <- DrivingAge(25)
rawInt <- #^ age
processInteger(rawInt) //extract then pass
PROMOTE VS STRING
Two different conversions:
text <- $age //String representation: "25" raw <- #^ age //Base type value: Integer 25
Both are useful but serve different purposes.
See Q257 for constrained type overview. See Q25 for promote operator basics. See Q722 for type hierarchy details.
Example
#!ek9 defines module qa.advancedtypes.constrainedpromote defines type DrivingAge as Integer constrain as >= 16 and <= 100 Name as String constrain as matches /^[a-zA-Z -]+$/ defines function <?- Accepts an Integer — cannot take DrivingAge directly. -?> processInteger() as pure -> intValue as Integer <- result as String: `Raw integer: ${intValue}` defines program ConstrainedPromoteDemo() stdout <- Stdout() age <- DrivingAge(25) // === PROMOTE TO BASE TYPE === rawInt <- #^ age stdout.println(`Promoted DrivingAge to Integer: ${rawInt}`) // === PASS TO FUNCTION EXPECTING BASE TYPE === extracted <- #^ age output <- processInteger(extracted) stdout.println(output) // === STRING CONVERSION VS PROMOTE === asText <- $age stdout.println(`String conversion: ${asText}`) asInteger <- #^ age stdout.println(`Promote to Integer: ${asInteger}`) // === STRING-CONSTRAINED: use $ not #^ === //String has no promote operator, so Name does not either. //Use string conversion ($) instead: name <- Name("Alice Smith") nameAsStr <- $name stdout.println(`Name as String: ${nameAsStr}`) // === ISSET STILL WORKS === isValid <- age? stdout.println(`DrivingAge is set: ${isValid}`) // === HASHCODE === hashVal <- #? age stdout.println(`Hashcode: ${hashVal}`)
Common mistakes
E50060 — String has no toUpperCase() method in EK9. Use upperCase() instead. See ek9 -h E50060 for details.
Incorrect:
output <- processInteger(extracted).toUpperCase()
Correct:
output <- processInteger(extracted)
E50060 — Name has no getValue() method in EK9. Use the $ prefix operator to convert to String. See ek9 -h E50060 for details.
Incorrect:
nameAsStr <- name.getValue()
Correct:
nameAsStr <- $name
Other ways to ask this
- What does the #^ promote operator do with constrained types?
- How do I convert a DrivingAge back to an Integer?
- Why can't I promote a constrained enumeration to its base enum?
Coming from another language?
Java: no constrained types, no promote concept. Explicit casting or wrapper.getValue() for custom wrappers. Python: no type constraints, no promote. Rust: newtype pattern uses .0 field access or Into trait for conversion. Go: type conversion syntax T(value) converts between compatible types. Kotlin: value classes use underlying property access. EK9: promote (#^) is the explicit operator for crossing constrained type boundaries — returns the base type value, available on value-constrained types but blocked on constrained enumerations.
Keywords: base-type, boundary, constrained, convert, disconnected, enum, explicit, extract, promote