Types & Variables

Understanding Strada's type system and variable declarations.

Type System Overview

Strada is strongly typed. Every variable has a declared type that is checked at compile time.

Type Description Example
int64-bit signed integer (tagged pointer, zero heap allocation)42, -17
num64-bit floating point3.14, -0.5
strUTF-8 string"hello"
arrayDynamic array[1, 2, 3]
hashKey-value map{"a" => 1}
scalarGeneric type (any value)Any value
voidNo value (function returns)-
undefUndefined valueundef
dynamicContext-sensitive return typeFunction returns

Dynamic Return Type

The dynamic return type allows functions to return different types based on calling context, similar to Perl's wantarray():

func flexible() dynamic {
    if (core::wantarray()) {
        my array @r = (1, 2, 3);
        return @r;
    }
    return 42;
}

my array @arr = flexible();  # (1, 2, 3)
my int $val = flexible();    # 42

Context functions: core::wantarray(), core::wantscalar(), core::wanthash()

Sigils

Like Perl, Strada uses sigils to identify variable types:

$ - Scalar

Single values: integers, floats, strings, references, objects

@ - Array

Ordered lists of values

% - Hash

Key-value maps (associative arrays)

Variable Declaration

Variables are declared with my followed by type and sigil:

# Scalar variables ($ sigil)
my int $count = 0;
my num $price = 19.99;
my str $name = "Alice";
my scalar $anything = 42;

# Array variables (@ sigil)
my array @numbers = [1, 2, 3];
my array @empty = [];

# Hash variables (% sigil)
my hash %config = {
    "host" => "localhost",
    "port" => 8080
};
Declaration without initialization Variables can be declared without an initial value. They will be undef until assigned.
my int $x;  # $x is undef
$x = 10;     # Now $x is 10

Constants

Use const to declare compile-time constants:

# Global constants (compile to C #define)
const int MAX_SIZE = 100;
const str VERSION = "1.0.0";
const num PI = 3.14159;

# Sigil is optional for const
const int LIMIT = 50;      # Without sigil
const int $LIMIT = 50;   # With sigil - same effect

# Local constants
func example() void {
    const int LOCAL_MAX = MAX_SIZE / 2;
    # ...
}
Zero overhead for global constants Global constants with literal values compile to C #define macros, so there's no runtime overhead.

Package-Scoped Variables (our)

Use our to declare package-scoped global variables backed by the runtime global registry. Unlike my globals, our variables are accessible across dynamically loaded modules.

# Declare our variables at file level
our int $count = 0;
our str $name = "hello";
our int $no_init;          # Defaults to undef

# In another package
package Config;
our str $host = "localhost";  # Registry key: "Config::host"
our int $port = 8080;

package main;

func modify() void {
    $count = 42;              # Writes to global registry
    $count += 5;              # Compound assignment works
    $name .= " world";       # String append works
}

func main() int {
    say($count);              # 0
    modify();
    say($count);              # 47
    return 0;
}
our vs my at package level my globals compile to C global variables — fast but not visible across import_lib boundaries. our globals use the runtime registry — slightly slower but accessible from any module via core::global_get("pkg::name").

Integers (int)

Integers use tagged pointer representation: they are encoded directly in the pointer with zero heap allocation. This makes integer arithmetic, comparisons, loop counters, and array indexing extremely fast with no memory management overhead.

my int $a = 42;
my int $b = -17;
my int $hex = 0xFF;      # Hexadecimal: 255
my int $oct = 0o755;     # Octal: 493
my int $bin = 0b1010;    # Binary: 10

# Arithmetic
my int $sum = $a + $b;
my int $mod = $a % 5;     # Modulo: 2
my int $pow = 2 ** 10;   # Power: 1024

Floating Point (num)

my num $pi = 3.14159;
my num $sci = 1.5e10;    # Scientific notation
my num $neg = -0.001;

# Math operations
my num $sqrt = math::sqrt(16);     # 4.0
my num $sin = math::sin($pi);     # ~0
my num $floor = math::floor(3.7); # 3

Strings (str)

my str $s1 = "Hello";
my str $s2 = 'Single quotes also work';

# Escape sequences (in double quotes)
my str $newline = "Line 1\nLine 2";
my str $tab = "Col1\tCol2";
my str $quote = "She said \"Hi\"";

# Concatenation
my str $full = $s1 . " World";

# Repetition
my str $repeated = "ab" x 3;  # "ababab"

# String functions
my int $len = strlen($s1);           # 5
my str $upper = uc($s1);            # "HELLO"
my str $lower = lc($s1);            # "hello"
my str $sub = substr($s1, 0, 3);    # "Hel"
my int $pos = index($s1, "ll");    # 2

Arrays (array)

# Declaration
my array @nums = [1, 2, 3, 4, 5];
my array @mixed = [1, "two", 3.0];
my array @nested = [[1, 2], [3, 4]];

# Pre-allocate capacity for performance
my array @big[1000];  # Empty array with capacity for 1000 elements

# Access elements (use $ sigil for single element)
my int $first = $nums[0];      # 1
my int $last = $nums[-1];     # 5 (negative index)

# Modify elements
$nums[0] = 10;

# Array functions
push(@nums, 6);                 # Add to end
my scalar $popped = pop(@nums);  # Remove from end
unshift(@nums, 0);              # Add to beginning
my scalar $shifted = shift(@nums); # Remove from beginning

my int $length = len(@nums);    # Get length
my str $joined = join(",", @nums); # Join to string
my array @sorted = sort(@nums);  # Sort array
reverse(@nums);                  # Reverse in place

# Destructuring - unpack array into variables
my ($a, $b, $c) = @nums;           # Basic destructuring
my (int $x, str $y) = @mixed;    # With explicit types
my ($first, $second) = get_pair();  # From function return
Array Access Sigil When accessing a single element, use $array[index], not @array[index]. The @ sigil is for the whole array.

Hashes (hash)

# Declaration
my hash %person = {
    "name" => "Alice",
    "age" => 30,
    "city" => "NYC"
};

# Pre-allocate capacity for performance
my hash %cache[500];  # Empty hash with capacity for ~500 entries

# Access values (use $ sigil for single value)
my str $name = $person{"name"};    # "Alice"

# Add/modify values
$person{"email"} = "alice@example.com";
$person{"age"} = 31;

# Hash functions
my array @keys = keys(%person);        # Get all keys
my array @vals = values(%person);      # Get all values

# Check if key exists
if (exists(%person, "email")) {
    say("Has email");
}

# Delete a key
delete(%person, "city");
Hash Access Syntax Use $hash{key} for element access, NOT %hash{key}. Using %hash{key} is a syntax error.

References

References are created with the backslash operator \:

# References to variables
my int $x = 42;
my scalar $ref = \$x;     # Reference to scalar

my array @arr = [1, 2, 3];
my scalar $aref = \@arr;   # Reference to array

my hash %h = {"a" => 1};
my scalar $href = \%h;    # Reference to hash

# Dereference with arrow
say($aref->[0]);      # 1
say($href->{"a"});    # 1

# Anonymous references
my scalar $anon_arr = [1, 2, 3];    # Array reference
my scalar $anon_hash = {"x" => 1};  # Hash reference

Type Conversion

# String to int
my int $n = int("42");

# Int to string (automatic via concatenation)
my str $s = "" . 42;

# Explicit string conversion
my str $str = stringify(42);

The scalar Type

The scalar type can hold any value and is useful for generic programming:

func print_anything(scalar $val) void {
    say($val);
}

print_anything(42);
print_anything("hello");
print_anything([1, 2, 3]);