Skip to content

Data Types

Raven is a statically-typed language with a rich type system that provides safety and expressiveness.

Primitive Types

Integer (int)

64-bit signed integers.

let age: int = 25;
let count: int = -10;
let maxValue: int = 9223372036854775807;

Float (float)

64-bit floating-point numbers.

let pi: float = 3.14159;
let temperature: float = 98.6;
let precision: float = 0.001;

Boolean (bool)

True or false values.

let isActive: bool = true;
let isComplete: bool = false;
let isValid: bool = (age > 18);

string (string)

UTF-8 encoded strings. Inside double-quoted literals, backslash escapes are supported (for example \", \\, \n, \r, \t, \0), so JSON-like payloads such as "{\"hello\":1}" parse as a single string value.

let name: string = "Alice";
let message: string = "Hello, World!";
let empty: string = "";
let json: string = "{\"hello\":1}";

Array Types

Arrays are collections of elements of the same type.

Integer Arrays

let numbers: int[] = [1, 2, 3, 4, 5];
let emptyNumbers: int[] = [];
let singleNumber: int[] = [42];

string Arrays

let names: string[] = ["Alice", "Bob", "Charlie"];
let words: string[] = ["Hello", "World"];

Boolean Arrays

let flags: bool[] = [true, false, true];
let results: bool[] = [];

Multi-dimensional arrays

Array types nest: each [] adds one dimension. Element types must match at every level.

// 2D: matrix of int
let grid: int[][] = [[1, 2, 3], [4, 5, 6]];
let empty2d: int[][] = [];                    // zero rows
let rows: int[][] = [[], []];                // two empty rows (needs explicit int[][])

// 3D and deeper
let cube: int[][][] = [[[1, 2]], [[3, 4]]];

Indexing chains left-to-right: matrix[row][col] reads an element; matrix[row][col] = value assigns to that cell. The same works for struct fields that hold arrays, for example point.values[i][j] = x.

Type checking: nested literals like [[], []] are only valid when the variable has an explicit multi-dimensional type (for example int[][]), so the checker knows each inner [] is an int[].

User-Defined Types

Structs

Custom data structures with named fields.

struct Person {
    name: string,
    age: int,
    isActive: bool
}

struct Point {
    x: float,
    y: float
}

// Usage
let person: Person = Person { 
    name: "Alice", 
    age: 25, 
    isActive: true 
};

let point: Point = Point { x: 10.5, y: 20.0 };

Struct Methods

Structs can have methods defined with impl blocks. Each method receives self as the first parameter.

struct Person {
    name: string,
    age: int
}

impl Person {
    fun greet(self) -> string {
        return format("Hello, {}!", self.name);
    }

    fun have_birthday(self) -> void {
        self.age = self.age + 1;
    }
}

let p: Person = Person { name: "Alice", age: 30 };
print(p.greet());      // "Hello, Alice!"
p.have_birthday();     // Mutates p in place
  • Methods must have self as the first parameter
  • self refers to the struct value the method is called on
  • Mutations to self persist when the receiver is a variable

Enums

Custom types with a set of named variants.

enum HttpStatus {
    OK,
    NotFound,
    InternalError,
    BadRequest
}

enum Color {
    Red,
    Green,
    Blue,
    Yellow
}

// Usage
let status: HttpStatus = HttpStatus::OK;
let color: Color = Color::Red;

Type Inference

Raven can infer types in some cases, but explicit typing is recommended for clarity.

// Explicit typing (recommended)
let name: string = "Alice";
let age: int = 25;

// Type inference (works but less clear)
let name = "Alice";  // Inferred as string
let age = 25;        // Inferred as int

Type Checking

Raven performs static type checking at compile time.

let name: string = "Alice";
let age: int = 25;

// This would cause a type error:
// let result: int = name + age;  // Error: can't add string and int

// Correct way:
let result: string = format("{} is {} years old", name, age);

Type Conversion

Raven provides built-in functions for type conversion.

let number: int = 42;
let text: string = format("{}", number);  // Convert int to string

let input: string = "123";
// Note: Raven doesn't have built-in string-to-number conversion yet
// This would be added in future versions

Void Type

The void type represents the absence of a value, used for functions that don't return anything.

fun greet(name: string) -> void {
    print(format("Hello, {}!", name));
    // No return statement needed
}

Type Safety

Raven's type system prevents many common errors:

  • No null pointers - All variables must be initialized
  • No type confusion - Can't accidentally mix types
  • Array bounds checking - Prevents buffer overflows
  • Immutable by default - Variables can be reassigned but not mutated in place

Best Practices

  1. Always use explicit types for function parameters and return values
  2. Use descriptive names for struct fields and enum variants
  3. Initialize variables when declaring them
  4. Use appropriate types for your data (int for counts, float for measurements)
  5. Leverage type checking to catch errors early

Next: Control Flow - Conditional statements and loops