Strings & Characters
GX strings are powerful out of the box — interpolation, built-in methods, and O(1) length access. No strlen loops, no format specifiers.
The str Type
Strings in GX are fat strings — they store both a pointer to the text and the length:
fn main() {
var greeting = "Hello, GX!"
print("Text: {greeting}\n")
print("Length: {greeting.len}\n")
}
Getting the length is instant — no scanning for null terminators.
String Interpolation
Put any expression inside {} in a string:
fn main() {
var name = "Alice"
var age = 28
var score = 95.5
print("Name: {name}\n")
print("Age: {age}\n")
print("Score: {score}\n")
print("{name} is {age} years old with a score of {score}\n")
}
Interpolation works with variables, expressions, and function calls — anything that produces a value.
Escape Sequences
Special characters use backslash escapes:
| Escape | Meaning |
|---|---|
\n | Newline |
\t | Tab |
\\ | Backslash |
\" | Double quote |
\0 | Null character |
fn main() {
print("Line 1\nLine 2\n")
print("Column A\tColumn B\n")
print("She said \"hello\"\n")
print("Path: C:\\Users\\GX\n")
}
String Concatenation
Use + to join strings:
fn main() {
var first = "Hello"
var second = " World"
var combined = first + second
print("{combined}\n")
}
The char Type
Single characters use single quotes:
fn main() {
var letter:char = 'A'
var digit:char = '7'
print("letter = {letter}\n")
print("digit = {digit}\n")
}
Built-in String Methods
GX strings come with methods for common operations — no imports needed:
Searching
fn main() {
var text = "Hello, World!"
print("find 'World': {text.find(\"World\")}\n") // 7
print("contains 'Hello': {text.contains(\"Hello\")}\n") // true
print("starts_with 'He': {text.starts_with(\"He\")}\n") // true
print("ends_with '!': {text.ends_with(\"!\")}\n") // true
print("count 'l': {text.count(\"l\")}\n") // 3
}
Extracting and Trimming
fn main() {
var text = " Hello, World! "
print("trimmed: '{text.trim()}'\n")
print("sub(2,7): '{text.sub(2, 7)}'\n")
}
Transforming
fn main() {
var text = "Hello, World!"
print("upper: {text.upper()}\n")
print("lower: {text.lower()}\n")
print("replace: {text.replace(\"World\", \"GX\")}\n")
print("repeat: {text.repeat(3)}\n")
}
Splitting
fn main() {
var csv = "apple,banana,cherry"
var parts = csv.split(",")
print("Parts ({parts.len}):\n")
for (var part in parts) {
print(" - {part}\n")
}
}
Try it — Play with string methods in the Playground.
Expert Corner
Why fat strings? Traditional C strings are null-terminated — finding the length requires walking every character (strlen is O(n)). GX’s str stores { const char* ptr; int64_t len }, so .len is O(1). This also enables safe slicing without copying: sub(2, 7) returns a view into the original string.
Zero-copy vs scratch-buffer methods: Methods like find, contains, sub, trim, starts_with, and ends_with never allocate memory — they work directly on the existing string data. Methods like upper, lower, replace, and repeat use an internal scratch buffer since they need to produce modified text.
C interop: Use .cstr to get a null-terminated const char* for passing to C functions. Use .ptr when you have a C function that accepts a pointer and length separately. GX automatically converts between str and cstr at function call boundaries.
String interpolation is resolved at parse time. The parser only triggers interpolation when { is followed by an identifier character (a-z, A-Z, _), digit, (, -, or !. This means GLSL shader code like void main() { } inside strings works untouched — the space after { prevents interpolation.