How do conversion and introspection operators work in EK9?
← Operators and Expressions · Ref: Q242
EK9 provides conversion and introspection operators that extract information from objects. All are pure, take 0 arguments, and return strictly enforced types.
STRING CONVERSION ($)
The $ operator returns a String representation. It is called implicitly in string interpolation.
operator $ as pure <- rtn as String: ...
When you write `${myObj}`, the compiler calls the $ operator.
JSON CONVERSION ($$)
The $$ operator returns a JSON representation as a String. The JSON type has this built-in.
operator $$ as pure <- rtn as String: ...
HASHCODE (#?)
The #? operator returns an Integer hash code for use in Dict keys and equality checking.
operator #? as pure <- rtn as Integer: ...
ISSET (?)
The ? operator returns Boolean indicating whether the object has a meaningful, usable value.
operator ? as pure <- rtn as Boolean: ...
This is central to EK9's tri-state semantics (absent, present-unset, present-set).
PROMOTE (#^)
The #^ operator returns a DIFFERENT type (type promotion). It MUST return a type different from self. The compiler uses this for automatic type widening.
operator #^ as pure <- rtn as Float: ...
PREFIX AND SUFFIX (#< and #>)
The #< operator extracts a prefix, the #> operator extracts a suffix. On String, #< returns the first character and #> returns the last character.
first <- #< fullName last <- #> fullName
EMPTY AND LENGTH
The 'empty' operator returns Boolean (true if the object is empty). The 'length' operator returns Integer (size/count).
if empty collection stdout.println("Nothing here") size <- length myList
CLOSE
The 'close' operator performs resource cleanup. It is pure and returns nothing.
See Q25 for the promote operator in detail. See Q96 for class operators. See Q116 for default operator generation. See Q238 for the complete operator set. See Q245 for a complete custom type example.
Example
defines module qa.operators.conversion defines class Money amount <- Float() currency <- String() Money() as pure -> amount as Float currency as String this.amount :=: amount this.currency :=: currency operator $ as pure <- rtn as String: `${currency} ${amount}` operator #? as pure <- rtn as Integer: #?amount + #?currency override operator ? as pure <- rtn as Boolean: amount? and currency? operator #^ as pure <- rtn as Float: Float(amount) operator <=> as pure -> other as Money <- rtn as Integer: amount <=> other.amount operator == as pure -> other as Money <- rtn as Boolean: amount == other.amount and currency == other.currency defines program ConversionDemo() stdout <- Stdout() price <- Money(19.99, "USD") // === STRING CONVERSION $ (implicit in interpolation) === stdout.println(`Price: ${price}`) // === ISSET ? === stdout.println(`Is set: ${price?}`) // === HASHCODE #? === hash <- #? price stdout.println(`Hash: ${hash}`) // === PROMOTE #^ === floatValue as Float: price stdout.println(`Promoted to Float: ${floatValue}`) // === PREFIX AND SUFFIX ON STRING === name <- "Hello" first <- #< name last <- #> name stdout.println(`Prefix: ${first}`) stdout.println(`Suffix: ${last}`) // === LENGTH === text <- "Hello World" size <- length text stdout.println(`Length: ${size}`)
Common mistakes
E50060 — String has no size() method. Use the length prefix operator or .length() method for string length. See ek9 -h E50060 for details.
Incorrect:
size <- text.size()
Correct:
size <- length text
E07500 — Conversion operators like $, #?, and ? must be marked 'as pure' because they extract information without side effects. Omitting 'as pure' triggers E07500. See ek9 -h E07500 for details.
Incorrect:
operator $
Correct:
operator $ as pure
E07550 — The #? (hashcode) operator must return Integer. Returning String instead triggers E07550. See ek9 -h E07550 for details.
Incorrect:
<- rtn as String: #?amount + #?currency
Correct:
<- rtn as Integer: #?amount + #?currency
Other ways to ask this
- How does string interpolation use the $ operator in EK9?
- What do the prefix and suffix operators do in EK9?
- How do I convert my type to String or JSON in EK9?
Coming from another language?
Java: toString() for String, no built-in JSON, hashCode() for hash, equals() check not isSet, no prefix/suffix operators. Python: __str__() and __repr__() for String, json.dumps() for JSON, __hash__() for hash, __bool__() for truthiness. Rust: Display trait for String, serde for JSON, Hash trait for hash, no isSet concept. Go: String() method by convention, json.Marshal() for JSON, no hash interface. Kotlin: toString() for String, no built-in JSON operator, hashCode() for hash. JavaScript: toString() for String, JSON.stringify() for JSON, no custom hash. EK9: $ returns String, $$ returns JSON, #? returns Integer hashcode, ? returns Boolean isSet, #^ returns promoted type, #< prefix, #> suffix, empty returns Boolean, length returns Integer.
Keywords: operator, interpolation, length, backtick, json, empty, string, prefix, suffix, conversion, expression, isset, close, introspection, hashcode, promote