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
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: constrained, boundary, base-type, explicit, extract, convert, disconnected, promote, enum