Skip to content

builtins

Builtins are always available without importing any module.

Function Signature Description
println (value T) Print value with newline. Accepts any type.
print (value T) Print value without newline. Accepts any type.
eprintln (value T) Print to stderr with newline. Accepts any type.
eprint (value T) Print to stderr without newline. Accepts any type.
flush () Flush buffered stdout so partial-line output appears immediately.

All types are printable: string, i64, f64, bool, arrays, maps, structs, and pointers.

stdout is buffered. print output may not appear until a newline is written (on a terminal) or the buffer fills (on a pipe or file); call flush() to force it out for prompts, progress indicators, and spinners. system flushes stdout and stderr before running the child so output is not reordered.

Function Signature Description
input () -> string Read line from stdin. Flushes stdout first so a preceding print prompt is visible.
Function Description
i128, i256 Convert to wide signed integers (struct-based, 128/256-bit)
u128, u256 Convert to wide unsigned integers (struct-based, 128/256-bit)
Function Signature Description
len (collection T) -> i64 Length of array, map, or string (byte length for strings, not character count)
type_of (value T) -> string Returns the Grayscale type name as a string (e.g. "i64", "u64", "f64", "string", "i128", "u256"). Accepts any type.
size_of (Type) -> i64 Size of type in bytes
fields (instance T) -> [string] Returns the field names of a struct as an array of strings in declaration order. Accepts struct instances and pointers to structs.
copy (value T) -> T Create deep copy. Accepts any type.
new (Type) -> ^Type Allocate zero-initialized value of any type on the heap arena
ref (variable T) -> T Create a transparent reference (alias) to a variable. The return type is inferred and cannot be explicitly annotated. Reads and writes through the reference affect the original. Mutability is determined by the declaration (mut or const).
addr (variable T) -> ^T Get memory address of a variable
raw (variable T) -> ^T Get unchecked pointer — skips nil-check panics and const-source write protection
error (code ErrorCode, message string = "") -> Error Create error value
assert (condition bool, message string = "") Terminate with P0075 if condition is false. Message is optional.
panic (message string) Terminate with error message
exit (code i64) Exit program with code
range (start i64, end i64, step i64 = 1) -> Range Create integer range; step defaults to 1
cast (value T, Type) -> Type Explicit type conversion
to_char (s string, index i64) -> char Return the char at character position index (not byte position). The char is a 32-bit Unicode codepoint; use cast(c, i64) on the result for its numeric value. Panics if index is out of bounds.
char_count (s string) -> i64 Return the number of Unicode characters (codepoints) in a string. Unlike len(), which returns byte count, char_count() counts decoded UTF-8 characters.
c_string (ptr ^u8) -> string Convert a C char* return value to a Grayscale string (for C interop)
embed (path string) -> string Read a file at compile time and return its contents as a string literal baked into the binary
system (command string) -> i64 Run a shell command and return its exit code. Returns -1 if killed by signal.

Reference behavior with ref():

The ref() function creates a reference to an existing value. The mutability of the reference depends on the variable declaration:

import @arrays
do main() {
mut arr [i64] = {1, 2, 3}
// mut ref is mutable - can modify through the reference
mut r1 = ref(arr)
arrays.append(r1, 4) // OK - modifies arr
// const ref is read-only - can read but not modify
const r2 = ref(arr)
mut val = r2[0] // OK - can read
// arrays.append(r2, 5) // ERROR - cannot modify through const ref
// const ref sees changes made to the original
arrays.append(arr, 6)
println(r2[4]) // Prints 6 - r2 sees the change
}

Mutability rules:

Reference declaration Source Allowed?
mut r = ref(x) mut yes
const r = ref(x) mut yes, read-only view of a mutable source
const r = ref(x) const yes
mut r = ref(x) const no; you cannot get a mutable reference to a const source. Use copy(x) to obtain an independent mutable instance.

Argument requirement: ref() requires a variable, struct field, array index, or pointer dereference; anything with a stable address. Literals, call results, and arithmetic expressions are rejected. The same rule applies to addr() and raw(), and the check recurses through member/index chains, so ref(some_call().field) is validated end-to-end. Indexing a dynamic [T] array is also rejected for all three (addr(arr[i]), raw(arr[i]), ref(arr[i])) — the backing store relocates when the array grows, leaving the pointer dangling. A fixed-size [T,N] array element is allowed, since its storage never moves.

assert() — runtime assertion

assert() checks a condition at runtime. If the condition is false, the program terminates immediately with error code P0075 and prints "panic[P0075]: assertion failed" to stderr. An optional second argument provides a message appended to the output.

do main() {
mut x i64 = 1
mut items [i64] = {1}
mut connected bool = true
assert(x > 0, "x must be positive")
assert(len(items) > 0, "list cannot be empty")
assert(connected) // message is optional
}

assert() is a global builtin — no import required.

Rules:

  • The condition must be a bool. Passing a non-bool is a compile-time error (E5026).
  • The optional message must be a string. Passing any other type is a compile-time error (E5026).
  • If the condition is true, the program continues normally. assert() has no return value.

Runtime error code: P0075

Function Signature Description
sleep_s (seconds i64) Sleep for seconds
sleep_ms (ms i64) Sleep for milliseconds
sleep_ns (ns i64) Sleep for nanoseconds

embed(path string) -> string

embed() reads a file from disk at compile time and bakes its entire contents into the binary as a string literal. The resulting value is available as a string at runtime with no file I/O overhead.

The path is resolved relative to the directory of the source file containing the embed() call. Absolute paths are also accepted. The argument must be a string literal; variables and expressions are rejected at compile time. If the file does not exist or cannot be read when the compiler runs, it is a compile-time error.

embed() is valid at file scope (as a const initializer) or inside a function body.

// Embed a file at file scope, baked into the binary at compile time
// const LICENSE string = embed("../../LICENSE")
// const DEFAULT_CONFIG string = embed("config/defaults.json")
// do main() {
// // Also valid inside a function
// const shader string = embed("shaders/vertex.glsl")
// println(LICENSE)
// }
do main() {}

The embedded file is read once during compilation. Changes to the file after compilation have no effect on the binary. The compiler resolves the path relative to the .gray source file, not the current working directory when running grayc.