Skip to content

Type Casting & Coercion

1. The as Function

The as function performs explicit type conversion. It takes a type symbol and a value, returning the value cast to that type.

(as 'type-symbol value)

Supported type symbols:

Symbol Type Description
'i16 16-bit integer Short integer
'i32 32-bit integer Standard integer
'i64 64-bit integer Long integer (default)
'u8 unsigned 8-bit Byte values
'f32 32-bit float Single precision; an f64 past its range saturates to ±3.40e+38
'f64 64-bit float Double precision (default)
'b8 Boolean true / false
'str String Variable-length text
'sym Symbol Dictionary-encoded string
'date Date Days since 2000-01-01
'time Time Milliseconds since midnight
'timestamp Timestamp Nanoseconds since 2000-01-01T00:00:00
'timespan Duration Signed count of nanoseconds
'guid GUID 16-byte unique identifier

F32 literals use a trailing lowercase e: 42e, 1.5e, or -1.5e. Scientific notation keeps its exponent: 1e3 is F64, while 1e3e is F32. F32 vectors require a suffix on each non-null element: [1e 2e 0Ne]. Finite values beyond the F32 range saturate just as casts do. F32 values print with the suffix so parsing the output preserves the element type; the configured display precision still controls decimal rounding.

Casting F32 to STR instead produces plain numeric text without the literal suffix (for example, (as 'STR 1.5e) returns "1.5"). It uses nine significant digits so casting the string back to F32 preserves the value.

Numeric casts:

; Integer to float
(as 'f64 42)          ; 42.0

; Float to integer (truncates)
(as 'i64 3.14)        ; 3

; Narrow to wide integer
(as 'i16 100)         ; 100i16

Boolean casts:

; Integer to boolean
(as 'b8 1)          ; true
(as 'b8 0)          ; false

; Boolean to integer
(as 'i64 true)        ; 1
(as 'i64 false)       ; 0

String and symbol casts:

; String to symbol
(as 'sym "hello")    ; 'hello

; Symbol to string
(as 'str 'hello)     ; "hello"

Temporal casts from strings:

; Parse date from ISO string
(as 'date "2024.01.15")         ; 2024.01.15

; Parse time from string
(as 'time "12:30:00")           ; 12:30:00.000

; Parse timestamp (ISO 8601 input accepted; display uses the `D` separator)
(as 'timestamp "2024-01-15T12:30:00.000")  ; 2024.01.15D12:30:00.000000000

Vector casts: as maps element-wise over vectors.

Casting to STR produces a flat string vector from a vector or a LIST of atoms. Each outer element must convert to one string atom. A nested vector or LIST cell is rejected with a type error; this cast does not implicitly format or flatten a whole inner collection into a string cell.

; Cast an integer vector to float
(as 'f64 [1 2 3])     ; [1.0 2.0 3.0]

; Cast a float vector to integer
(as 'i64 [1.5 2.7 3.9])  ; [1 2 3]

2. The type Function

The type function returns the type name of a value as a symbol. For vectors, it returns the element type.

(type 42)                ; 'i64
(type 3.14)              ; 'f64
(type "hello")           ; 'str
(type 'hello)            ; 'sym
(type true)               ; 'b8
(type [1 2 3])           ; 'I64  (uppercase = vector type)
(type [AAPL GOOG])       ; 'SYM
(type [1.0 2.0])         ; 'F64
(type 2024.01.15)        ; 'date
(type 12:30:00.000)      ; 'time

Note

type returns lowercase for atoms ('i64, 'f64, 'sym, 'b8) and uppercase for vectors ('I64, 'F64, 'SYM). The cast function as accepts both 'sym and 'symbol.

For tables, type returns 'TABLE:

(type (table [a] (list [1])))  ; 'TABLE

Use type to branch on value types at runtime or to validate input before casting.

3. Implicit Coercion Rules

Rayfall performs automatic type promotion in certain contexts. These coercions happen silently — no explicit as needed.

Coercion rules

  • i64 + f64 → f64: Arithmetic between integers and floats promotes to float.
  • bool → i64: Booleans coerce to 1/0 in arithmetic contexts.
  • i64 → bool: In boolean contexts (if, cond), 0 is false, non-zero is true.
  • Narrower → wider: Comparisons across numeric types promote the narrower operand.
  • No string coercion: Strings never implicitly convert to numbers. Use as explicitly.
; Integer + float promotes to float
(+ 1 2.0)               ; 3.0
(* 3 1.5)               ; 4.5

; Boolean in arithmetic
(+ 10 true)              ; 11
(sum [true false true])   ; 2

; Boolean context
(if 42 "yes" "no")      ; "yes"
(if 0 "yes" "no")       ; "no"

; Cross-type comparison
(> 5 3.0)               ; true  (i64 promoted to f64)

; String + number: ERROR (no implicit coercion)
; (+ "42" 1)  ; type error — use (+ (as 'i64 "42") 1)

4. String ↔ Type Conversions

Strings can be parsed into numeric, temporal, and symbol types with as. Conversely, any value can be cast to a string.

; Parse integers and floats from strings
(as 'i64 "42")          ; 42
(as 'f64 "3.14")        ; 3.14

; Number to string
(as 'str 42)            ; "42"
(as 'str 3.14)          ; "3.14"

; Parse date from ISO string (YYYY-MM-DD)
(as 'date "2024.01.15")          ; 2024.01.15

; Parse time (HH:MM:SS.mmm)
(as 'time "12:30:00.000")        ; 12:30:00.000

; Parse timestamp (ISO 8601 input accepted; display uses the `D` separator)
(as 'timestamp "2024-01-15T12:30:00.000")  ; 2024.01.15D12:30:00.000000000

; Boolean to/from string
(as 'str true)           ; "true"
(as 'b8 "true")       ; true  (non-empty string → true)
(as 'b8 "")           ; false (empty string → false)

5. Null Semantics in Casting

Null values propagate through casts to nullable types. BOOL/B8 and U8 have no null value: a numeric or temporal null casts to true for BOOL/B8 and 0x00 for U8. The result is an ordinary non-null value, consistently for atoms, vectors, lists, and query column casts. Empty strings cast to BOOL/B8 as false. Invalid numeric string parses raise a domain error.

(as 'B8 0Nl)             ; true
(as 'B8 [0 0Nl 1])       ; [false true true]
(as 'U8 0Nl)             ; 0x00
(nil? (as 'U8 0Nl))      ; false
; Casting a typed null produces a typed null
(as 'f64 0Ni)           ; 0Nf  (null i32 → null f64)
(as 'i64 0Nf)           ; 0Nl  (null f64 → null i64)

; Null to string
(as 'str 0Ni)           ; null string

; Invalid string parse → domain error
(as 'i64 "not-a-number")  ; error: domain
(as 'date "bad-date")     ; error: domain

Null literals by type

  • 0Ni — null i32
  • 0Nl — null i64
  • 0Nh — null i16
  • 0Nf — null f64
  • 0Ne — null f32
  • 0Ng — null guid (the all-zero GUID)
  • 0Nd — null date
  • 0Nt — null time
  • 0Np — null timestamp
  • 0Nn — null timespan

SYM has no 0N literal (0Ns does not parse): its null is the empty symbol, written '. (nil? ') is true, and it prints as ', so a printed vector such as [a ' b] reads back as the same value. STR's null is the empty string "".

Use nil? to test for null values: (nil? 0Ni) returns true.

; Null propagation through arithmetic
(+ 0Ni 10)              ; 0Nl  (null propagates; i32 + i64 → i64)
(* 0Nf 2.0)             ; 0Nf

; Null in vectors — sentinel null elements stay null.
; The null literal must match the vector's element type (0Nl for i64).
(+ [1 0Nl 3] 10)          ; [11 0Nl 13]

6. Symbol vs String

Rayforce has two string representations with different performance characteristics. Choosing the right one matters for large datasets.

Feature RAY_SYM ('sym) RAY_STR ('str)
Storage Dictionary-encoded (integer indices into global intern table) Variable-length (inline for 12 bytes or fewer, pooled for longer)
Comparison Integer comparison (fast) Byte comparison with 4-byte prefix rejection
Best for Categorical data with repeated values (status, country, product) Unique or freeform text (names, descriptions, URLs)
Group-by speed Very fast (integer hashing) Slower (string hashing)
Memory Low for high-repeat columns (one copy per unique value) Proportional to total text length
; Creating symbol and string values
(set s 'Active)         ; symbol literal
(set t "hello world")   ; string literal

; Converting between them
(as 'sym "Active")     ; 'Active
(as 'str 'Active)      ; "Active"

; Symbol vectors (common in tables)
(set statuses ['Active 'Inactive 'Active 'Pending])
(type statuses)          ; 'SYM  (uppercase = vector)

Rule of thumb

Use 'sym for columns where you expect many repeated values (status codes, categories, tickers). Use 'str for freeform text (descriptions, addresses, log messages).

7. Date/Time Types

Rayforce represents calendar points and clock times with DATE, TIME, and TIMESTAMP, and nanosecond durations with TIMESPAN. All use integer storage:

Type Internal Epoch Literal Format
date i32 Days since 2000-01-01 2024.01.15
time i32 Milliseconds since midnight 12:30:00.000
timestamp i64 Nanoseconds since 2000-01-01 midnight 2024.01.15D12:30:00.000000000
timespan i64 Nanoseconds of duration 1D, 0D01:00:00.000000000

date and time are 32-bit counts (of days and of milliseconds). A time is not limited to one day: 48:00:00.000 and negative values are valid, up to about ±596 hours. A result past the 32-bit range keeps its low 32 bits, the same for an atom and for a vector cell, so (* 25 24:00:00.000) is -593:02:47.296.

Subtracting two timestamps returns TIMESPAN. Cast the difference with as 'I64 when an integer nanosecond count is needed. A duration may be added to a timestamp, scaled by an integer, or used as an xbar width. See Timespan for operator result types and migration details.

Date arithmetic:

; Add days to a date
(+ 2024.01.15 1)        ; 2024.01.16
(+ 2024.01.15 30)       ; 2024.02.14

; Subtract dates to get days between
(- 2024.01.15 2024.01.01)  ; 14

; Create a date range
(+ 2024.01.01 (til 7))   ; [2024.01.01 2024.01.02 ... 2024.01.07]

Casting between temporal types:

; Date to timestamp (midnight)
(as 'timestamp 2024.01.15)  ; 2024.01.15D00:00:00.000000000

; Timestamp to date (strips time) — note the `D` separator in the literal
(as 'date 2024.01.15D12:30:00.000)  ; 2024.01.15

; Date to integer (days since epoch)
(as 'i64 2024.01.15)      ; 8780

8. GUID Type

GUIDs are 16-byte unique identifiers displayed as hex strings. They are useful for primary keys, correlation IDs, and distributed systems.

guid takes a count and returns a GUID vector of that length:

; Generate N random GUIDs
(guid 0)                  ; []                      (empty vector)
(guid 1)                  ; [daa76c35-...-dfb2fcab]  (one random GUID; random each time)
(guid 3)                  ; three random GUIDs

; GUIDs support equality comparison
(set g (guid 1))
(== g g)                  ; [true]

; Type check
(type (guid 1))           ; 'GUID  (uppercase = vector)

9. sym-name Function

The sym-name function resolves integer symbol IDs into symbols. Given a symbol atom, it returns the symbol unchanged. Given an i64 (a raw sym table index), it returns the corresponding symbol.

(sym-name 'hello)        ; 'hello  (passthrough)
(sym-name 0)              ; resolves sym ID 0 to its symbol

; Useful for building dynamic strings from symbols
;; To get a string from a symbol, use cast:
(as 'str 'hello)          ; "hello"

10. Practical Examples

CSV Type Fixing

After loading a CSV, columns often arrive as strings. Cast them to proper types:

; Load CSV (all columns as strings by default)
(write "/tmp/rayforce-types-trades.csv"
  "sym,price,qty,date\nAAPL,150.5,100,2024.03.01\nGOOG,2800.0,50,2024.03.10\n")
(set raw (.csv.read [STR STR STR STR] "/tmp/rayforce-types-trades.csv"))

; Cast columns to proper types
(set trades (table [price qty date sym]
  (list (as 'f64 (at raw 'price))
        (as 'i64 (at raw 'qty))
        (as 'date (at raw 'date))
        (as 'sym (at raw 'sym)))))

Date Arithmetic for Analytics

; Find records in the last 30 days
(set today 2024.03.15)
(set cutoff (- today 30))

(select {from: trades where: (>= date cutoff)})

Building Typed Vectors

; Build a date vector from strings
(set dates (as 'date ["2024.01.01" "2024.02.01" "2024.03.01"]))
; [2024.01.01 2024.02.01 2024.03.01]

; Build a symbol vector from strings
(set categories (as 'sym ["A" "B" "A" "C"]))
; ['A 'B 'A 'C]

Type-Safe Table Construction

; Construct a well-typed table
(set orders (table
  [id product price date]
  (list
    [1 2 3]
    ['Widget 'Gadget 'Widget]
    [9.99 24.50 9.99]
    (+ 2024.01.01 [0 1 2]))))

; Inspect the table shape. On a table, `meta` reports only the kind and the
; column count — it does not return per-column types.
(meta orders)
; {type:TABLE len:4}   (len = number of columns)

; To see a single column's element type, use `type`:
(type (at orders 'price))   ; 'F64

Next Steps