Skip to Content
Cloth

Conversions and casts

Cloth separates numeric conversion from runtime reference casts.

Implicit numeric widening

An existing numeric value converts implicitly only through these rules:

SourceImplicit destination
Signed integerLarger signed integer
Unsigned integer, including byteLarger unsigned integer
Unsigned integerSigned integer with strictly greater width
float32float64

Equal-width signed and unsigned types do not implicitly convert. Neither do integers and floating-point types. Unsuffixed numeric literals may instead adopt an expected type directly when representable. A suffixed literal already has the exact type named by its suffix and follows the ordinary widening table.

Explicit numeric conversion

Write the destination type around the operand:

int32 count = 120; int8 small = int8(count); float64 approximate = float64(count); int32 whole = int32(approximate);

The operand is evaluated once. This is a numeric operation, not an object constructor.

ConversionRuntime behavior
Integer to integerTrap unless the mathematical value fits
Float to integerTruncate toward zero, then check range; NaN and infinities trap
Integer to floatRound to nearest, ties to even
float64 to float32Round once; finite overflow traps, NaN and infinities are preserved

Explicit floating conversions accept underflow and ordinary precision loss. The checked form does not wrap, saturate, reinterpret bits, or convert to bool.

A literal conversion is checked at compile time and adopts its destination type directly. For example, int8(127) is valid and int8(128) is a compile-time error.

A suffix fixes the conversion’s source type. int64(1i8) converts an int8 value; int8(128i16) is rejected because the checked conversion cannot represent the int16 value. Wrapping and saturating conversions likewise receive the suffix-selected source type.

Wrapping and saturating integer conversion

Integer targets also provide explicit conversion modes:

int8 wrapped = int8::wrap(300); // 44 int8 limited = int8::sat(300); // 127 uint8 residue = uint8::wrap(-1); // 255 uint8 nonnegative = uint8::sat(-1); // 0

Target::wrap(value) computes the mathematical value modulo 2 raised to the target width. A signed target interprets the resulting bits as two’s-complement. Target::sat(value) clamps the mathematical value to the target’s inclusive minimum and maximum.

The target and operand must both be non-nullable integer types. int, uint, and byte are accepted according to their ordinary aliases and widths. The operand is evaluated exactly once without adopting the target type, so int8::wrap(300) converts the default int32 literal. These modes do not trap for range; the ordinary Target(value) form remains the checked default.

Reference widening

Derived classes widen to base classes. Conforming classes widen to interfaces, and interfaces widen to their parent interfaces. All managed references widen to object. Compatible nullable forms widen to nullable destinations.

Arrays are invariant. User[] does not become object[]; it may widen as a whole to object. Primitives, enums, and structs box when converted to object; normal locals, fields, parameters, results, and arrays retain unboxed value storage.

Runtime type tests

object value = "Cloth"; bool isText = value is string; string? text = value as string?; if (text != null) { println(text); } object count = 42; bool isInt32 = count is int32; int32? restored = count as int32?;

is T requires a non-null runtime-checkable reference target. It returns false for null and for a mismatching runtime type; it does not trap or smart-cast the binding to T.

as T? requires a nullable target. It preserves the reference on success and returns null on failure. as T with a non-null target is invalid.

Checks follow class ancestry and declared interface conformance. Statically impossible conversions, such as between unrelated concrete class types, are rejected. A primitive, enum, or struct target checks the exact boxed type and copies the payload on successful as; it never performs numeric widening or narrowing. Runtime checks targeting arrays are unsupported.