Built-in Functions (UFCS)
saQut provides a set of built-in functions on three types: strings, arrays, and structs. You do not import them and you do not define them; they are always available. This page documents each one with a runnable example.
If you have not used a “method” before, start with the next section. For the signatures on their own, jump to the quick reference tables.
Calling a built-in
Section titled “Calling a built-in”You call a built-in with the dot call syntax: write the value, a dot, the method name, and any extra arguments in parentheses:
string name = "saqut";print(name.upper()); // "SAQUT"Read this as: “take name, and apply upper to it.” The value on the left of
the dot is what the function works on; anything inside the parentheses are extra
arguments:
string s = "hello world";print(s.replace("world", "saQut")); // s is the value; "world" and // "saQut" are the two argumentsNot object-orientation. The dot here is syntax only. saQut has no classes, objects, or methods-on-types in the OOP sense;
name.upper()is sugar for a plain function call that reads left to right.
Because most string built-ins return a new value, you can chain calls, each result flows into the next dot:
string title = "Hello World Post";print(title.lower().replace(" ", "-")); // "hello-world-post"String functions
Section titled “String functions”Strings in saQut are immutable: none of these functions change the original string. They return a new string (or a number/bool). If you want to keep a result, assign it to a variable.
string s = "hello";s.upper(); // computes "HELLO" but THROWS IT AWAY, s is unchangeds = s.upper(); // THIS keeps it, now s is "HELLO"length() (how long is the string?)
Section titled “length() (how long is the string?)”print("hello".length()); // 5print("".length()); // 0Counts the characters (Unicode code points) in the string. Text is stored
as UTF-8, but the string methods index by code point, not by byte, so
length() matches what you see:
print("café".length()); // 4 (code points)print("café".toBuffer().length()); // 5 (bytes)length(), substring(), charAt(), and indexOf() all use the same
code-point index, so they agree with each other. When you really need bytes,
convert with toBuffer() (or encode() from the utf8 module).
Grapheme note. One code point is not always one visible glyph. A base letter followed by a combining accent is two code points, so it counts as 2.
upper() / lower() (change case)
Section titled “upper() / lower() (change case)”print("Hello, World".upper()); // "HELLO, WORLD"print("Hello, World".lower()); // "hello, world"These transform ASCII letters only (a-z / A-Z). Accented and
non-Latin letters pass through unchanged:
print("café".upper()); // "CAFé", the 'é' is NOT uppercasedtrim() (remove surrounding whitespace)
Section titled “trim() (remove surrounding whitespace)”Strips spaces, tabs, and newlines from both ends (not the middle):
print("|" + " hi ".trim() + "|"); // "|hi|"print("a b c".trim()); // "a b c", inner spaces stayCommon use: cleaning up user input before comparing it.
string input = " yes ";if (input.trim() == "yes") { print("confirmed");}replace(old, new) (swap text, everywhere)
Section titled “replace(old, new) (swap text, everywhere)”This function has more behavior worth spelling out, so here it is in full detail.
replace finds every occurrence of old in the string and returns a new
string with each one swapped for new. The original is untouched.
string s = "the cat sat on the mat";string r = s.replace("at", "og");print(r); // "the cog sog on the mog"print(s); // "the cat sat on the mat", original unchangedWalk through what happened: replace("at", "og") scanned the text and found
"at" inside c-at, s-at, and m-at, replacing each with "og" to give
cog, sog, mog. The word the has no at, so it stayed.
It replaces all matches, not just the first. If you only wanted the first
one, replace is not the tool, it always does every match.
print("a-a-a".replace("a", "X")); // "X-X-X" (all three)The replacement can be shorter, longer, or empty. An empty replacement deletes the matched text:
print("hello world".replace("l", "")); // "heo word", every 'l' removedprint("2024-01-15".replace("-", "/")); // "2024/01/15"print("a".replace("a", "bb")); // "bb", grew from 1 to 2 charsMatches don’t overlap. After a match is replaced, scanning continues after the inserted text, so the new text is never re-scanned:
print("aaa".replace("aa", "b")); // "ba", first "aa"→"b", one "a" left overA practical example, turning a sentence into a URL slug:
string title = "Hello World Post";string slug = title.lower().replace(" ", "-");print(slug); // "hello-world-post"Notice the chaining: title.lower() returns a string, and we immediately
call .replace(...) on that result. Because each call returns a new string, you
can line them up left to right.
substring(start, length) (cut out a piece)
Section titled “substring(start, length) (cut out a piece)”Returns a piece of the string starting at code-point index start, taking
length characters. Indices start at 0.
Read the second argument carefully. It is a length (a count), not an end position.
substring(2, 3)means “start at index 2 and take 3 characters”, it does not mean “from index 2 up to index 3”.
string s = "abcdef"; // index: a=0 b=1 c=2 d=3 e=4 f=5print(s.substring(0, 2)); // "ab" (start 0, take 2)print(s.substring(2, 3)); // "cde" (start 2, take 3)print(s.substring(1, 4)); // "bcde" (start 1, take 4)print(s.substring(0, 0)); // "" (take 0 characters)If you ask for more characters than remain, you get whatever is left, with no error:
print("abcdef".substring(4, 99)); // "ef" (only 2 characters remained)A start that is past the end of the string, or negative, is an error you can
catch with try/catch.
repeat(count) (glue N copies together)
Section titled “repeat(count) (glue N copies together)”print("ab".repeat(3)); // "ababab"print("=".repeat(10)); // "==========", handy for separatorsprint("x".repeat(0)); // "" (zero copies = empty string)charAt(index) (the character at one position)
Section titled “charAt(index) (the character at one position)”Returns a one-character string at code-point index index (starting at 0).
saQut has no separate “single character” type here, so you get back a length-1
string.
string s = "saqut";print(s.charAt(0)); // "s"print(s.charAt(4)); // "t"To loop over a string character by character (ASCII):
string word = "hi!";for (int i = 0; i < word.length(); i = i + 1) { print(word.charAt(i));}// s → h, i, ! (one per line)indexOf(sub) (where does it appear?)
Section titled “indexOf(sub) (where does it appear?)”Searches for sub and returns the code-point index of its first occurrence.
If
sub is not found, it returns null, so the result type is int?
(nullable). You must check for null before using the number.
string s = "hello world";int? at = s.indexOf("world");if (at != null) { print(at); // 6}
int? missing = s.indexOf("xyz");if (missing == null) { print("not found");}Returning null (instead of the C convention of -1) means the “not found”
case can’t be silently mistaken for a real index, the compiler forces you to
handle it.
contains(sub) (is it in there?)
Section titled “contains(sub) (is it in there?)”A yes/no version of indexOf. Returns a bool, so it reads nicely in an if:
if (email.contains("@")) { print("looks like an email");}startsWith(prefix) / endsWith(suffix)
Section titled “startsWith(prefix) / endsWith(suffix)”Check the beginning or end of a string. Both return bool:
string file = "report.pdf";print(file.startsWith("report")); // trueprint(file.endsWith(".pdf")); // trueprint(file.endsWith(".txt")); // falsesplit(separator) (break into an array)
Section titled “split(separator) (break into an array)”Splits the string wherever separator appears and returns a string[] of
the pieces:
string csv = "apple,banana,cherry";string[] parts = csv.split(",");print(parts.length()); // 3print(parts[0]); // "apple"print(parts[2]); // "cherry"Empty pieces are kept. Two separators in a row produce an empty string between them:
string data = "a,b,,c";string[] fields = data.split(",");print(fields.length()); // 4print("[" + fields[2] + "]"); // "[]", the empty field is preservedsplit pairs naturally with a loop to process each piece:
string line = "10 20 30 40";string[] nums = line.split(" ");int total = 0;for (int i = 0; i < nums.length(); i = i + 1) { int? n = nums[i] as int?; // parse each piece if (n != null) { total = total + n; }}print(total); // 100Array functions
Section titled “Array functions”Arrays are reference types, several of these functions change the array in place (marked “mutates” below). Because arrays are shared, an in-place change is visible through every variable that points at the same array.
length() (how many elements?)
Section titled “length() (how many elements?)”int[] a = [10, 20, 30];print(a.length()); // 3Use it as the upper bound of a loop so your code adapts to any size:
for (int i = 0; i < a.length(); i = i + 1) { print(a[i]);}push(value) (add to the end (mutates))
Section titled “push(value) (add to the end (mutates))”Appends value to the end and returns the index it landed at:
int[] a = [1, 2];a.push(3); // a is now [1, 2, 3]int idx = a.push(4); // a is now [1, 2, 3, 4]print(idx); // 3, the index of the new elementpop() (remove the last element (mutates))
Section titled “pop() (remove the last element (mutates))”Removes the final element and returns it. Classic stack behavior (last in, first out):
int[] a = [1, 2, 3];int last = a.pop(); // last = 3, a is now [1, 2]print(last); // 3print(a.length()); // 2insert(index, value) (add in the middle (mutates))
Section titled “insert(index, value) (add in the middle (mutates))”Inserts value so that it ends up at position index, shifting everything
after it one place to the right:
int[] a = [10, 20, 30];a.insert(1, 99); // a is now [10, 99, 20, 30]print(a[1]); // 99remove(index) (take one out (mutates))
Section titled “remove(index) (take one out (mutates))”Removes the element at index and returns it, closing the gap:
int[] a = [10, 20, 30];int gone = a.remove(0); // gone = 10, a is now [20, 30]print(gone); // 10contains(value) (is the value present?)
Section titled “contains(value) (is the value present?)”Returns bool:
int[] a = [1, 2, 3];print(a.contains(2)); // trueprint(a.contains(9)); // falseindexOf(value) (where is the value?)
Section titled “indexOf(value) (where is the value?)”Returns the index of the first match, or null if the value isn’t there
(type int?, exactly like the string version):
string[] names = ["ali", "veli", "deli"];int? at = names.indexOf("veli");if (at != null) { print(at); } // 1slice(start, end) (copy out a range)
Section titled “slice(start, end) (copy out a range)”Returns a new array containing elements from index start up to but not
including end. The original is left alone.
Unlike
string.substring(which takes a length),array.slicetakes an end index and excludes it: the range is[start, end).
int[] a = [10, 20, 30, 40, 50];int[] mid = a.slice(1, 3); // indices 1 and 2 → [20, 30]print(mid.length()); // 2print(mid[0]); // 20print(a.length()); // 5, original unchangedconcat(other) (join two arrays)
Section titled “concat(other) (join two arrays)”Returns a new array with the elements of both, back to back:
int[] a = [1, 2];int[] b = [3, 4];int[] both = a.concat(b); // [1, 2, 3, 4]print(both.length()); // 4reverse() (flip the order (mutates))
Section titled “reverse() (flip the order (mutates))”Reverses the array in place and also returns the same array reference:
int[] a = [1, 2, 3];a.reverse(); // a is now [3, 2, 1]print(a[0]); // 3Because it mutates, remember that other variables pointing at the same array see the change too:
int[] a = [1, 2, 3];int[] b = a; // b and a are the SAME arraya.reverse();print(b[0]); // 3, b changed as wellclear() (empty it out (mutates))
Section titled “clear() (empty it out (mutates))”Removes every element, leaving an empty array:
int[] a = [1, 2, 3];a.clear();print(a.length()); // 0Struct functions
Section titled “Struct functions”Every struct, no matter what fields it has, comes with two functions for turning it into text. They are handy for debugging and for producing output other programs can read.
toJson() (machine-readable JSON)
Section titled “toJson() (machine-readable JSON)”struct Point { int x; int y; }
int main() { Point p; p.x = 10; p.y = 20; print(p.toJson()); // {"x":10,"y":20} return 0;}Use this when another tool or program needs to consume the data.
dump() (human-readable debugging)
Section titled “dump() (human-readable debugging)”Point p;p.x = 10;p.y = 20;print(p.dump()); // a readable, labelled view of the fieldsUse this when you are the one reading the output while hunting a bug.
Quick reference
Section titled “Quick reference”String methods
Section titled “String methods”| Method | Returns | What it does |
|---|---|---|
s.length() |
int |
Number of characters (code points) |
s.upper() |
string |
ASCII letters to uppercase |
s.lower() |
string |
ASCII letters to lowercase |
s.trim() |
string |
Remove whitespace from both ends |
s.replace(old, new) |
string |
Replace all occurrences |
s.substring(start, length) |
string |
length chars starting at start |
s.repeat(count) |
string |
The string repeated count times |
s.charAt(index) |
string |
One-character string at index |
s.indexOf(sub) |
int? |
First index, or null if absent |
s.contains(sub) |
bool |
Is sub present? |
s.startsWith(prefix) |
bool |
Does it begin with prefix? |
s.endsWith(suffix) |
bool |
Does it end with suffix? |
s.split(sep) |
string[] |
Break into pieces on sep |
Array methods
Section titled “Array methods”| Method | Returns | Mutates? | What it does |
|---|---|---|---|
a.length() |
int |
no | Number of elements |
a.push(v) |
int |
yes | Append v, return its index |
a.pop() |
E |
yes | Remove & return the last element |
a.insert(i, v) |
int |
yes | Insert v at index i |
a.remove(i) |
E |
yes | Remove & return element at i |
a.slice(start, end) |
E[] |
no | New array, range [start, end) |
a.concat(b) |
E[] |
no | New array of a then b |
a.reverse() |
E[] |
yes | Reverse in place |
a.contains(v) |
bool |
no | Is v present? |
a.indexOf(v) |
int? |
no | First index, or null |
a.clear() |
void |
yes | Remove all elements |
(E is the array’s element type, int for int[], string for
string[], and so on.)
Struct methods
Section titled “Struct methods”| Method | Returns | What it does |
|---|---|---|
s.toJson() |
string |
Machine-readable JSON |
s.dump() |
string |
Human-readable debug output |
The print() host function
Section titled “The print() host function”print() stands apart from the methods above: it is not a method on a type but
a host function, a function implemented in C++ inside the compiler and
exposed to your program through saQut’s FFI seam. It takes one value of any type
and writes it out:
print(42); // 42print(3.14); // 3.14print("text"); // textprint(true); // 1 (bool prints as 1 / 0)print is the first host function exposed through the FFI seam. Other
standard-library functions (files, math, and so on) are exposed through the same
host-function mechanism.
