A cast needs a clear destination type.
These are supported cast targets:
BoolIntStringCharFloatError
Not every source type can convert to every target.
An annotation gives the cast its target:
count Int = cast! text
label String = cast count
Without that annotation, the compiler cannot know which conversion you want:
count = cast text
The second form is invalid.
Casts can also receive a target from a function parameter, return slot, field or another immediate typed destination.
Explicit casts target compiler-supported builtin types:
Bool
Int
String
Char
Float
Error
A type being a valid target does not mean every source type can convert to it.
Builtin cast table
Int -> Float (infallible): Numeric conversion to finite FloatInt -> String (infallible): Base-10 signed integer textFloat -> String (infallible): Moth's stable Float formatterBool -> String (infallible): "true" or "false"Char -> String (infallible): One Unicode scalar as UTF-8 textChar -> Int (infallible): Unicode scalar code pointString -> Error (infallible): Error message from the text with code 0Error -> String (infallible): The error message onlyFloat -> Int (fallible): Truncate toward zero, then require signed 32-bit rangeInt -> Char (fallible): Require a valid Unicode scalar valueString -> Int (fallible): Parse the complete Moth integer text grammarString -> Float (fallible): Parse the complete numeric grammar and require a finite resultString -> Bool (fallible): Trim surrounding whitespace, then accept exactly lowercase true or falseString -> Char (fallible): Require exactly one Unicode scalar
No other builtin source-target pair is implied by the target list.
Same-type casts are invalid.
Target source
The target must come from the immediate typed boundary.
Valid target boundaries include:
- an annotated declaration or assignment
- an explicit return slot
- a concrete function parameter
- a struct or choice field
- a default value
- a typed collection or map entry
- a
then arm whose enclosing value-producing block has an explicit receiver
Generic parameter slots are not cast targets. Generic inference does not look through cast.
These positions do not supply cast targets:
- conditions
- loop conditions
- assertions
- template interpolation
- operator operands
- expression statements
- untyped declarations
value = cast source
if cast value:
io.line("invalid")
;
[: [cast value]]
The forms above are invalid because no immediate builtin target exists.
Optional receiving contexts
A T? receiving context casts to inner T, then applies normal contextual wrapping to T?.
Optional source values are not automatically unwrapped.
In:
target T? = cast source catch:
then fallback
;
the recovery handler produces inner T. then none is invalid because recovery happens before optional wrapping.
Numeric and text details
String -> Int and String -> Float consume the whole string.- Numeric text rejects surrounding whitespace, uppercase exponent markers, unary plus, malformed separators, malformed exponents,
NaN and infinity spellings. String -> Float additionally rejects a grammar-valid non-finite result.String -> Int and Float -> Int must materialise inside -2147483648 through 2147483647.Float -> String normalizes -0.0 to 0 and uses lowercase exponent formatting when exponential notation is required.- Contextual
Int -> Float promotion remains separate from explicit casting, though explicit cast is valid from a naturally Int source to a Float target.