Built-in Functions

Complete reference for all built-in functions.

Output Functions

FunctionDescription
say($value)Print value with newline
print($value)Print value without newline
warn($msg)Print warning to stderr
die($msg)Print error and exit

String Functions

FunctionDescription
strlen($str)Return string length
substr($str, $start, $len)Extract substring
index($str, $substr)Find first occurrence, -1 if not found
rindex($str, $substr)Find last occurrence
uc($str)Convert to uppercase
lc($str)Convert to lowercase
ucfirst($str)Uppercase first character
lcfirst($str)Lowercase first character
trim($str)Remove leading/trailing whitespace
split($sep, $str)Split string into array
join($sep, @arr)Join array into string
chr($code)Character from ASCII code
ord($char)ASCII code from character
sprintf($fmt, ...)Formatted string (like C sprintf)
stringify($val)Convert value to string

String Repetition Operator (x)

The x operator repeats a string a given number of times. It has the same precedence as *, /, and %.

my str $dashes = "-" x 40;
say($dashes);  # "----------------------------------------"

my str $ab = "ab" x 3;
say($ab);  # "ababab"

# Useful for formatting
say("=" x 60);
say("  Report Title");
say("=" x 60);

Transliteration (tr///, y///)

The tr/// operator (alias y///) performs character-by-character transliteration. Unlike s///, it does not use regex — it maps individual characters from one set to another.

SyntaxDescription
$str =~ tr/abc/xyz/;Replace a with x, b with y, c with z (modifies in place)
$str =~ y/abc/xyz/;Same as tr/// (Perl alias)
my str $new = ($str =~ tr/abc/xyz/r);Return new string instead of modifying (with /r flag)

Flags

FlagDescription
cComplement — transliterate characters NOT in the search list
dDelete — delete characters with no replacement
sSqueeze — collapse duplicate replaced characters into one
rReturn — return new string, do not modify original
my str $text = "Hello World";

# ROT13
$text =~ tr/A-Za-z/N-ZA-Mn-za-m/;
say($text);  # "Uryyb Jbeyq"

# Lowercase to uppercase
my str $upper = "hello";
$upper =~ tr/a-z/A-Z/;
say($upper);  # "HELLO"

# Delete digits
my str $nodigits = "abc123def456";
$nodigits =~ tr/0-9//d;
say($nodigits);  # "abcdef"

# Squeeze repeated spaces
my str $spaced = "hello    world";
$spaced =~ tr/ / /s;
say($spaced);  # "hello world"

# Return modified copy (original unchanged)
my str $original = "hello";
my str $copy = ($original =~ tr/a-z/A-Z/r);
say($original);  # "hello" (unchanged)
say($copy);      # "HELLO"

Examples

my str $s = "  Hello World  ";
say(strlen($s));           # 15
say(trim($s));             # "Hello World"
say(substr($s, 2, 5));    # "Hello"
say(uc($s));               # "  HELLO WORLD  "
say(index($s, "World"));  # 8

my array @parts = split(" ", trim($s));
say(join("-", @parts));   # "Hello-World"

Array Functions

FunctionDescription
len(@arr)Return array length
scalar(@arr)Return array length (alias for len)
push(@arr, $val)Add element to end
pop(@arr)Remove and return last element
shift(@arr)Remove and return first element
unshift(@arr, $val)Add element to beginning
reverse(@arr)Reverse array elements in place
sort(@arr)Return sorted array
splice(@arr, $off, $len)Remove elements, return removed
splice(@arr, $off, $len, @repl)Remove and replace with @repl, return removed

splice() in Detail

The splice() function removes elements from an array and optionally replaces them. It returns an array of the removed elements.

my array @data = (10, 20, 30, 40, 50);

# Remove 2 elements starting at index 1
my array @removed = splice(@data, 1, 2);
# @removed = (20, 30), @data = (10, 40, 50)

# Replace 1 element at index 1 with two new elements
my array @arr = ("a", "b", "c", "d");
my array @repl = ("X", "Y");
splice(@arr, 1, 1, @repl);
# @arr = ("a", "X", "Y", "c", "d")

# Insert without removing (len = 0)
my array @list = (1, 2, 5);
my array @insert = (3, 4);
splice(@list, 2, 0, @insert);
# @list = (1, 2, 3, 4, 5)

Array Memory Management

FunctionDescription
core::array_capacity(@arr)Get current allocated capacity
core::array_reserve(@arr, $n)Ensure capacity for at least $n elements
core::array_shrink(@arr)Shrink capacity to match length

Pre-allocating Arrays

For performance, pre-allocate arrays when you know the approximate size:

my array @data[1000];  # Pre-allocate for 1000 elements
for (my int $i = 0; $i < 1000; $i++) {
    push(@data, $i);  # No reallocation needed
}

Array Transformations (map, grep, sort)

Strada supports Perl-style block expressions for powerful array transformations. The special variable $_ contains the current element.

ExpressionDescription
map { expr } @arrTransform each element
grep { cond } @arrFilter elements where condition is true
sort { $a <=> $b } @arrSort with custom comparison ($a, $b)
sort @arrSort alphabetically (default)

Map Examples

my array @nums = (1, 2, 3, 4, 5);

# Transform each element (double)
my array @doubled = map { $_ * 2 } @nums;
# Result: (2, 4, 6, 8, 10)

# Transform to strings
my array @strings = map { "Value: " . $_ } @nums;

Map with Fat Arrow (Creating Hashes)

The classic Perl idiom for building lookup hashes works in Strada:

my array @fruits = ("apple", "banana", "cherry");

# Create a lookup hash - the Perl way!
my hash %lookup = map { $_ => 1 } @fruits;
# %lookup is now {"apple" => 1, "banana" => 1, "cherry" => 1}

# Fast membership testing
if (exists($lookup{"apple"})) {
    say("Found apple!");
}

The fat arrow $_ => value creates a key-value pair. When assigned to a hash variable, these pairs become hash entries.

Grep Examples

my array @nums = (1, 2, 3, 4, 5, 6);

# Keep only even numbers
my array @evens = grep { $_ % 2 == 0 } @nums;
# Result: (2, 4, 6)

# Keep values greater than 3
my array @big = grep { $_ > 3 } @nums;
# Result: (4, 5, 6)

Sort Examples

my array @nums = (5, 2, 8, 1, 9);

# Sort ascending (numeric) - use spaceship operator
my array @asc = sort { $a <=> $b } @nums;
# Result: (1, 2, 5, 8, 9)

# Sort descending
my array @desc = sort { $b <=> $a } @nums;
# Result: (9, 8, 5, 2, 1)

# Default sort (alphabetical)
my array @alpha = sort @names;

Chaining Operations

my array @data = (5, 2, 8, 1, 9, 3, 7);

# Filter, transform, and sort in one pipeline
my array @result = sort { $a <=> $b } map { $_ * 10 } grep { $_ > 3 } @data;
# Result: (50, 70, 80, 90)

Hash Functions

FunctionDescription
keys(%hash)Return array of keys
values(%hash)Return array of values
exists(%hash, $key)Check if key exists (returns 1/0)
delete(%hash, $key)Remove key-value pair
each(%hash)Return next [key, value] pair; empty array when done
core::hash_default_capacity($n)Set default capacity for new hashes

each() Iterator

The each() function returns the next key-value pair from a hash as a two-element array [key, value]. When all pairs have been returned, it returns an empty array. The iterator resets when all entries have been traversed.

my hash %config = ();
$config{"host"} = "localhost";
$config{"port"} = 8080;
$config{"debug"} = 1;

# Iterate with each()
my array @pair = each(%config);
while (scalar(@pair) > 0) {
    say($pair[0] . " = " . $pair[1]);
    @pair = each(%config);
}
# Output (order may vary):
#   host = localhost
#   port = 8080
#   debug = 1

Pre-allocating Hashes

Pre-allocate hashes when you know the approximate size:

my hash %cache[500];  # Pre-allocate for ~500 entries

# Or set default for all new hashes:
core::hash_default_capacity(1000);

Hashes automatically resize for O(1) average lookup time.

Type Functions

FunctionDescription
int($val)Convert to integer
num($val)Convert to number
defined($val)Check if value is defined
ref($val)Return reference type or empty string
typeof($val)Return type as string
bless(\%h, $class)Associate hash ref with class
core::weaken($ref)Make $ref a weak reference (break circular refs)
core::isweak($ref)Returns 1 if $ref is weak, 0 otherwise

File I/O Functions

FunctionDescription
slurp($path)Read entire file as string
spew($path, $data)Write string to file
core::open($path, $mode)Open file, return filehandle
core::open(\$var, $mode)Open in-memory handle (ref-style, writeback on close)
core::open_str($content, $mode)Open in-memory handle from string
core::str_from_fh($fh)Extract string from memstream
core::readline($fh)Read line from filehandle
core::read($fd, $len)Read bytes from fd
core::write($fd, $data)Write bytes to fd
core::close($fd)Close file descriptor
core::seek($fd, $pos, $whence)Seek in file
core::tell($fd)Get current position
core::eof($fd)Check if at end of file
core::flush($fd)Flush file buffer
select($fh)Set default filehandle for print/say

select() — Default Filehandle

The select() function sets the default output filehandle. After calling select($fh), all print() and say() calls without an explicit filehandle will write to $fh instead of stdout.

my scalar $fh = core::open("output.log", "w");

# Redirect print/say to the file
select($fh);
say("This goes to output.log");
print("So does this");

# Restore stdout (pass undef or no argument)
select(undef);
say("Back to stdout");

core::close($fh);

Diamond Operator <$fh>

The diamond operator reads lines from a filehandle or socket. Context determines behavior:

SyntaxContextDescription
my str $line = <$fh>ScalarRead one line (strips newline)
my array @lines = <$fh>ArrayRead ALL lines into array
@lines = <$fh>ArrayRead ALL lines (assignment)
<$sock>AnyWorks with sockets too (strips \r\n)

Filehandle I/O

Say and print work with filehandles as the first argument:

SyntaxDescription
say($fh, $text)Write text with newline to filehandle/socket
print($fh, $text)Write text without newline to filehandle/socket

In-Memory I/O

Read from and write to strings using standard file handle operations. All I/O functions work transparently with in-memory handles.

# Read from a string
my scalar $fh = core::open_str("line1\nline2\n", "r");
my str $line = <$fh>;  # "line1"

# Write to a string buffer
my scalar $wfh = core::open_str("", "w");
say($wfh, "hello");
my str $result = core::str_from_fh($wfh);  # "hello\n"

# Reference-style (variable updated on close)
my str $output = "";
my scalar $wfh2 = core::open(\$output, "w");
say($wfh2, "data");
core::close($wfh2);  # $output = "data\n"

Math Functions (math::)

FunctionDescription
math::abs($n)Absolute value
math::floor($n)Round down
math::ceil($n)Round up
math::round($n)Round to nearest
math::sqrt($n)Square root
math::pow($base, $exp)Power
math::sin($n)Sine
math::cos($n)Cosine
math::tan($n)Tangent
math::log($n)Natural logarithm
math::log10($n)Base-10 logarithm
math::exp($n)e^n
math::rand()Random number 0-1
math::srand($seed)Seed random generator

System Functions (core::)

Process Control

FunctionDescription
core::exit($code)Exit with status code
core::fork()Fork process
core::exec($cmd, @args)Execute command
core::system($cmd)Run shell command
core::wait()Wait for child process
core::waitpid($pid)Wait for specific process
core::getpid()Get process ID
core::getppid()Get parent process ID
core::kill($pid, $sig)Send signal to process

Environment

FunctionDescription
core::getenv($name)Get environment variable
core::setenv($name, $val)Set environment variable
core::getcwd()Get current directory
core::chdir($path)Change directory

File System

FunctionDescription
core::stat($path)Get file info
core::mkdir($path)Create directory
core::rmdir($path)Remove directory
core::unlink($path)Delete file
core::rename($old, $new)Rename file
core::readdir($path)List directory
core::is_dir($path)Check if directory
core::is_file($path)Check if regular file
core::realpath($path)Get absolute path
core::dirname($path)Get directory part
core::basename($path)Get filename part
core::glob($pattern)Glob pattern matching

Time

FunctionDescription
core::time()Unix timestamp
core::localtime($ts)Convert to local time hash
core::gmtime($ts)Convert to GMT hash
core::sleep($secs)Sleep for seconds
core::usleep($usecs)Sleep for microseconds

Debugging

FunctionDescription
core::stack_trace()Get current call stack as string

Call Context (Dynamic Return Type)

FunctionDescription
core::wantarray()Returns 1 if called in array context
core::wantscalar()Returns 1 if called in scalar context (default)
core::wanthash()Returns 1 if called in hash context

Networking

FunctionDescription
core::socket_server($port)Create TCP server
core::socket_accept($fd)Accept connection
core::socket_connect($host, $port)Connect to server
core::gethostbyname($host)Resolve hostname
core::gethostbyname_all($host)Resolve hostname (all addresses)
core::gethostname()Get local hostname
core::getaddrinfo($host, $port)Advanced address resolution

SSL/TLS (ssl::)

Secure socket connections via OpenSSL. Build with: cd lib/ssl && make

FunctionDescription
ssl::connect($host, $port)Connect to TLS server
ssl::read($conn, $len)Read from TLS connection
ssl::write($conn, $data)Write to TLS connection
ssl::close($conn)Close TLS connection
ssl::http_get($host, $port, $path)Simple HTTPS GET request

SSL Example

my int $conn = ssl::connect("example.com", 443);
ssl::write($conn, "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n");
my str $response = ssl::read($conn, 4096);
ssl::close($conn);

# Or use the convenience function:
my str $page = ssl::http_get("example.com", 443, "/");

UTF-8 Introspection (utf8::)

Perl-compatible UTF-8 introspection functions. In Strada, all strings are stored as raw bytes (typically UTF-8). There is no separate "UTF-8 flag" like Perl.

FunctionDescription
utf8::is_utf8($str)Returns 1 if string is valid UTF-8, 0 otherwise
utf8::valid($str)Alias for is_utf8()
utf8::encode($str)No-op (strings are already bytes), returns the string
utf8::decode($str)Validates UTF-8; returns 1 if valid, 0 if not
utf8::upgrade($str)No-op (strings are already UTF-8), returns the string
utf8::downgrade($str)Returns string if ASCII-only, dies on non-ASCII
utf8::downgrade($str, 1)With fail_ok=1, returns undef instead of dying
utf8::unicode_to_native($cp)Identity mapping on modern systems

UTF-8 Example

my str $text = "Hello";
say(utf8::is_utf8($text));    # 1 (ASCII is valid UTF-8)
say(utf8::downgrade($text)); # "Hello" (ASCII-only, succeeds)

# Safe downgrade with fail_ok
my scalar $result = utf8::downgrade($text, 1);
if (!defined($result)) {
    say("Contains non-ASCII");
}

Signals

FunctionDescription
core::signal($sig, \&handler)Set signal handler
core::signal($sig, "IGNORE")Ignore signal
core::signal($sig, "DEFAULT")Reset to default

Dynamic Loading (FFI)

FunctionDescription
core::dl_open($lib)Load shared library
core::dl_sym($handle, $name)Get symbol address
core::dl_call_sv($fn, @args)Call Strada function (returns StradaValue)
core::dl_call_int_sv($fn, @args)Call Strada function (returns int)
core::dl_call_str_sv($fn, @args)Call Strada function (returns str)
core::dl_call_void_sv($fn, @args)Call Strada function (void return)
core::dl_call_version($fn)Get library version string
core::dl_close($handle)Unload library

FFI Example

# Load a Strada shared library
my int $lib = core::dl_open("./mylib.so");
my int $fn = core::dl_sym($lib, "my_function");
my scalar $result = core::dl_call_sv($fn, [$arg1, $arg2]);

Library Imports

For cleaner library imports, use import_lib, import_object, or import_archive:

use lib "lib";
import_lib "JSON.so";         # Runtime loading (dlopen)
import_object "Utils.o";      # Static linking
import_archive "DataLib.a";  # Static linking with bundled runtime

# Functions are now available with namespace syntax:
my str $json = JSON::encode(\%data);
my hash %data = JSON::decode($json);

Library Compilation

Compile Strada programs as libraries:

./strada --shared mylib.strada      # Creates mylib.so
./strada --object mylib.strada      # Creates mylib.o
./strada --static-lib mylib.strada  # Creates mylib.a (includes runtime)

C Interop (__C__ Blocks)

Embed raw C code directly in Strada programs using __C__ blocks:

Top-Level Blocks

For includes, globals, and C helper functions:

__C__ {
    #include <math.h>
    #include <openssl/ssl.h>

    static SSL_CTX *g_ctx = NULL;

    static int helper(int a, int b) {
        return a + b;
    }
}

Statement-Level Blocks

Inline C code inside functions with access to Strada variables:

func my_sqrt(num $x) num {
    __C__ {
        double val = strada_to_num(x);
        return strada_new_num(sqrt(val));
    }
}

Key C Functions

FunctionDescription
strada_to_int(sv)Extract int64_t from StradaValue*
strada_to_num(sv)Extract double from StradaValue*
strada_to_str(sv)Extract string (caller must free!)
strada_new_int(i)Create StradaValue* from int64_t
strada_new_num(n)Create StradaValue* from double
strada_new_str(s)Create StradaValue* from string
&strada_undefReturn undef value

Opaque Handle Pattern

Store C pointers in Strada int variables (64-bit):

func open_connection(str $host) int {
    __C__ {
        char *h = strada_to_str(host);
        SSL *conn = connect_ssl(h);
        free(h);
        // Store pointer as int
        return strada_new_int((int64_t)(intptr_t)conn);
    }
}

func close_connection(int $handle) void {
    __C__ {
        // Retrieve pointer from int
        SSL *conn = (SSL*)(intptr_t)strada_to_int(handle);
        SSL_free(conn);
        return &strada_undef;
    }
}

JSON Functions

FunctionDescription
json_encode($val)Convert to JSON string
json_decode($str)Parse JSON string

Package Syntax

SyntaxDescription
__PACKAGE__Current package name (runtime)
::func()Call func in current package (compile-time)
.::func()Alternate syntax for above
__PACKAGE__::func()Explicit form of above
use overload "+" => "method", ...;Operator overloading for current package

Example

package Calculator;

func add(int $a, int $b) int { return $a + $b; }

func compute(int $x, int $y) int {
    return ::add($x, $y);  # Calls Calculator_add
}

Moose-Style OOP Keywords

Strada provides a declarative OOP system inspired by Perl's Moose. See the OOP page for full details and examples.

SyntaxDescription
has ro type $name;Declare read-only attribute with getter
has rw type $name;Declare read-write attribute with getter and setter
has ro type $name (required);Required attribute (must be passed to constructor)
has rw type $name = default;Attribute with default value
extends Parent;Inherit from one or more parent classes
extends Parent1, Parent2;Multiple inheritance
with Role;Compose a role (mixin) into the class
before "method" func($self) void { }Run code before a method call
after "method" func($self) void { }Run code after a method call
around "method" func($self) void { }Wrap a method call entirely
Auto-Generated Constructor

When a package uses has declarations, the compiler automatically generates a new() constructor that accepts named arguments as alternating key-value pairs. If you define your own new(), the auto-generated one is skipped.

my scalar $obj = MyClass::new("name", "value", "age", 30);

core:: Namespace Alias

The core:: namespace is the preferred way to call system functions. It is an alias for the older sys:: namespace. The compiler normalizes core:: to sys:: at compile time, so there is zero overhead. Both namespaces work interchangeably.

core:: Call (preferred)Legacy sys:: Call
core::exit(0)sys::exit(0)
core::open($path, "r")sys::open($path, "r")
core::time()sys::time()
core::getenv("HOME")sys::getenv("HOME")
core::fork()sys::fork()

Use whichever namespace feels more natural. core:: is recommended for new code as it reads more clearly as "core language functionality."

# These are equivalent:
my int $pid = core::fork();
my int $pid = sys::fork();

my str $home = core::getenv("HOME");
my str $home = sys::getenv("HOME");

my int $now = core::time();
my int $now = sys::time();

Miscellaneous

FunctionDescription
dump($val)Debug print value structure
caller()Get caller information
eval($code)Evaluate Strada code string
$obj->isa($class)Check if object is instance of class
$obj->can($method)Check if object has method
$obj->$method()Dynamic method dispatch (name from variable)
local($var)Dynamic scoping for our variables

local() — Dynamic Scoping

The local() function provides dynamic scoping for our (package-global) variables. It saves the current value and automatically restores it when the enclosing scope exits. This is useful for temporarily overriding globals without affecting the rest of the program.

our int $verbose = 0;

func debug_section() void {
    local($verbose) = 1;  # Temporarily set to 1
    do_work();               # $verbose is 1 here
    # $verbose automatically restored to 0 on scope exit
}

func do_work() void {
    if ($verbose) {
        say("Doing work...");  # Prints when called from debug_section
    }
}

func main() int {
    do_work();        # $verbose is 0, nothing printed
    debug_section(); # $verbose is temporarily 1 inside
    do_work();        # $verbose is 0 again
    return 0;
}
local() vs my

local() provides dynamic scoping — the localized value is visible in the current function and all functions called from it. my provides lexical scoping — the variable is only visible in the current block. local() only works with our variables (package globals).

tie/untie/tied — Tied Hashes

The tie mechanism binds a hash variable to a class, allowing custom behavior for hash operations. When a hash is tied, all accesses (read, write, delete, exists, iteration) are dispatched to methods in the tied class.

FunctionDescription
tie(%hash, "ClassName", @args)Bind hash to class; calls TIEHASH(@args)
untie(%hash)Unbind hash from class
tied(%hash)Return the tied object, or undef if not tied

TIEHASH Methods

The tied class must implement these methods:

MethodDescription
TIEHASH(@args)Constructor — called by tie(), returns the tied object
FETCH($self, $key)Called when reading: $hash{$key}
STORE($self, $key, $val)Called when writing: $hash{$key} = $val
DELETE($self, $key)Called for: delete($hash{$key})
EXISTS($self, $key)Called for: exists($hash{$key})
FIRSTKEY($self)Called to start iteration (keys, each)
NEXTKEY($self, $lastkey)Called for subsequent keys during iteration
CLEAR($self)Called when hash is cleared

Example: Case-Insensitive Hash

package CIHash;

func TIEHASH() scalar {
    my hash %self = ();
    $self{"data"} = {};
    return bless(\%self, "CIHash");
}

func FETCH(scalar $self, str $key) scalar {
    return $self->{"data"}->{lc($key)};
}

func STORE(scalar $self, str $key, scalar $val) void {
    $self->{"data"}->{lc($key)} = $val;
}

package main;

func main() int {
    my hash %h = ();
    tie(%h, "CIHash");

    $h{"Name"} = "Alice";   # Calls CIHash::STORE
    say($h{"name"});         # Calls CIHash::FETCH -> "Alice"
    say($h{"NAME"});         # "Alice" (case insensitive)

    untie(%h);              # Unbind from class
    return 0;
}
Zero Overhead

When a hash is not tied, hash operations compile to the same code as before — no dispatch checks, no extra branches. The tied mechanism only adds overhead to hashes that are actually tied.

Compiler Flags

The Strada compiler (stradac) and wrapper (strada) support these flags:

FlagDescription
-r, --runCompile and run immediately
-c, --keep-cKeep generated .c file
-g, --debugInclude debug symbols
-p, --profileEnable function profiling
-w, --warningsShow compiler warnings
-t, --timingShow compilation phase timing
--sharedCompile as shared library (.so)
-L <path>Add library search path (high priority)
-LL <path>Add library search path (low priority)

Examples

# Compile and run
./strada -r program.strada

# Compile with debugging
./strada -g program.strada

# Compile with profiling
./strada -p program.strada
./program  # Prints profiling report on exit

# Check for warnings
./strada -w program.strada

# Create shared library
./strada --shared mylib.strada  # Creates mylib.so