Walrus is a dynamically-typed language with a rich set of built-in data types. This guide covers all available types and how to work with them.
Primitive types
Integers
Whole numbers without decimal points:
let count = 42;
let negative = -10;
let zero = 0;
println(count); // 42
println(type(count)); // int
Floats
Numbers with decimal points:
let pi = 3.14159;
let temperature = -273.15;
let percentage = 0.95;
println(pi); // 3.14159
println(type(pi)); // float
Walrus uses 64-bit floating-point numbers (f64) for all float operations.
Strings
Sequences of characters enclosed in double quotes:
let greeting = "Hello, World!";
let name = "Walrus";
let empty = "";
println(greeting);
println(len(greeting)); // 13
Escape sequences
Strings support common escape sequences:
println("She said \"Hello!\""); // She said "Hello!"
println("Path: C:\\\\Users"); // Path: C:\\Users
println("Line 1\nLine 2"); // Two lines
println("Tab:\there"); // Tab separated
Escape Result \"Double quote \\Backslash \nNewline \tTab \rCarriage return
String operations
// Concatenation
let full_name = "Alice" + " " + "Smith";
// Indexing (0-based)
let first_char = greeting[0]; // "H"
let last_char = greeting[-1]; // "!"
// Slicing
let substr = greeting[0..5]; // "Hello"
Booleans
True or false values:
let is_active = true;
let is_complete = false;
println(is_active); // true
println(type(is_active)); // bool
// Boolean operations
let result = true and false; // false
let result2 = true or false; // true
let result3 = not true; // false
Collection types
Lists
Ordered, mutable collections that can hold mixed types:
let numbers = [1, 2, 3, 4, 5];
let mixed = [1, "hello", true, 3.14];
let empty = [];
println(numbers); // [1, 2, 3, 4, 5]
println(len(numbers)); // 5
List operations
let items = [10, 20, 30, 40, 50];
// Positive indexing
println(items[0]); // 10 (first element)
println(items[2]); // 30
// Negative indexing
println(items[-1]); // 50 (last element)
println(items[-2]); // 40
// Slicing
println(items[1..4]); // [20, 30, 40]
println(items[0..2]); // [10, 20]
let nums = [1, 2, 3];
// Append elements
nums.push(4);
println(nums); // [1, 2, 3, 4]
// Update by index
nums[0] = 10;
println(nums); // [10, 2, 3, 4]
// Concatenation
let combined = [1, 2] + [3, 4];
println(combined); // [1, 2, 3, 4]
// In-place concatenation
let list = [1, 2];
list += [3, 4];
println(list); // [1, 2, 3, 4]
let fruits = ["apple", "banana", "cherry"];
// For-each loop
for fruit in fruits {
println(fruit);
}
// With index using range
for i in 0..len(fruits) {
println(f"{i}: {fruits[i]}");
}
Tuples
Immutable, ordered collections:
let point = (3, 4);
let person = ("Alice", 30, "Seattle");
println(point); // (3, 4)
println(point[0]); // 3
println(len(person)); // 3
Tuples are immutable. Once created, their elements cannot be modified: let coords = (10, 20);
coords[0] = 15; // Error: cannot modify tuple
Dictionaries
Key-value pairs (hash maps):
let person = {
"name": "Alice",
"age": 30,
"city": "Seattle"
};
println(person["name"]); // Alice
println(len(person)); // 3
Dictionary operations
let config = {};
// Add entries
config["debug"] = true;
config["port"] = 8080;
// Update entries
config["port"] = 3000;
// Merge dictionaries
let defaults = {"timeout": 30};
config += defaults;
println(config);
// {"debug": true, "port": 3000, "timeout": 30}
// Iterate over entries
for entry in config {
println(entry); // Each entry is a tuple: (key, value)
}
Dictionary keys must be strings. Values can be any type.
Ranges
Sequences of integers used primarily in loops:
// Exclusive range: 0 to 9
for i in 0..10 {
println(i);
}
// Range from variable
let n = 5;
for i in 0..n {
println(i); // 0, 1, 2, 3, 4
}
// Can be used with lists
let items = ["a", "b", "c", "d"];
for i in 0..len(items) {
println(f"{i}: {items[i]}");
}
Ranges are half-open intervals: a..b includes a but excludes b. // 1..5 produces: 1, 2, 3, 4 (NOT 5)
for i in 1..5 {
println(i);
}
Special types
void
Represents the absence of a value:
let result = void;
if result == void {
println("No value");
}
// Functions without return statement return void
fn do_something : {
println("Done");
// Implicitly returns void
}
Functions
Functions are first-class values in Walrus:
fn add : a, b {
return a + b;
}
// Assign function to variable
let operation = add;
// Call through variable
let result = operation(5, 3); // 8
println(type(add)); // function
Type checking
Use the type() built-in function to check a value’s type:
println(type(42)); // int
println(type(3.14)); // float
println(type("hello")); // string
println(type(true)); // bool
println(type([1, 2, 3])); // list
println(type((1, 2))); // tuple
println(type({"a": 1})); // dict
println(type(void)); // void
Type conversions
To string
Convert any value to a string:
let num = 42;
let text = str(num); // "42"
let items = [1, 2, 3];
let items_str = str(items); // "[1, 2, 3]"
println("Count: " + str(100));
Implicit conversions
Walrus performs automatic type conversions in certain contexts:
// Integer to float in arithmetic
let result = 5 / 2.0; // 2.5 (float)
// Automatic string conversion in print
println(42); // Prints "42"
println([1, 2, 3]); // Prints "[1, 2, 3]"
Working with mixed types
Collections can contain mixed types:
let mixed = [
42,
"text",
true,
[1, 2, 3],
{"key": "value"}
];
for item in mixed {
println(f"Type: {type(item)}, Value: {item}");
}
Best practices
Use appropriate collection types
Choose the right collection for your use case:
Lists : When you need ordered, mutable data
Tuples : For fixed-size, immutable groupings
Dictionaries : For key-value associations
Ranges : For sequential integer iteration
Check for void before using values
When a value might be void, check before using it: import "std/sys";
let home = sys.env_get("HOME");
if home != void {
println(f"Home: {home}");
} else {
println("HOME not set");
}
When debugging type-related issues, use type() to inspect values: let value = some_function();
println(f"Got type: {type(value)}");
Next steps
Variables Learn how to declare and assign variables
Operators Explore arithmetic, comparison, and logical operators