Examples - ThornLang/JavaThorn GitHub Wiki

ThornLang Examples and Tutorials

This page contains practical examples and tutorials to help you learn ThornLang through hands-on coding.

Table of Contents

Basic Examples

Hello, World! Variations

// 1. Simple hello world
print("Hello, World!");

// 2. With a function
$ greet(name: string) {
    print("Hello, " + name + "!");
}
greet("World");

// 3. With string building
$ buildGreeting(names: Array[string]): string {
    greeting = "Hello";
    for (name in names) {
        greeting = greeting + ", " + name;
    }
    return greeting + "!";
}
print(buildGreeting(["Alice", "Bob", "Charlie"]));

// 4. With a class
class Greeter {
    $ init(greeting: string) {
        defaultGreeting = greeting;
    }
    
    $ greet(name: string) {
        print(this.defaultGreeting + ", " + name + "!");
    }
}

greeter = Greeter("Bonjour");
greeter.greet("Marie");

Working with Variables

// Variable declaration and types
name: string = "ThornLang";
version: number = 0.2;
isAwesome: boolean = true;
features: Array[string] = ["fast", "expressive", "dual-mode"];

// Immutable constants
@immut PI = 3.14159;
@immut GOLDEN_RATIO = 1.618;
@immut APP_CONFIG = {
    "name": "MyApp",
    "version": "1.0.0",
    "debug": true
};

// Type inference
x = 42;              // Inferred as number
y = "hello";         // Inferred as string
z = [1, 2, 3];      // Inferred as Array[number]

// Null handling
optional: string = null;
defaultName = optional ?? "Anonymous";
print(defaultName);  // "Anonymous"

Control Flow Examples

// If-else conditions
$ checkAge(age: number) {
    if (age < 0) {
        print("Invalid age!");
    } else if (age < 13) {
        print("Child");
    } else if (age < 20) {
        print("Teenager");
    } else if (age < 60) {
        print("Adult");
    } else {
        print("Senior");
    }
}

// Pattern matching
$ getDayType(day: string): string {
    return match day {
        "Saturday" => "Weekend",
        "Sunday" => "Weekend",
        "Monday" => "Weekday",
        "Tuesday" => "Weekday",
        "Wednesday" => "Weekday",
        "Thursday" => "Weekday",
        "Friday" => "TGIF!",
        _ => "Invalid day"
    };
}

// Loops
// For loop
for (i = 1; i <= 5; i += 1) {
    print("Count: " + i);
}

// While loop
countdown = 10;
while (countdown > 0) {
    print(countdown + "...");
    countdown -= 1;
}
print("Blast off!");

// For-in loop
fruits = ["apple", "banana", "orange"];
for (fruit in fruits) {
    print("I like " + fruit);
}

Intermediate Examples

Array Manipulation

// Array operations showcase
$ arrayDemo() {
    // Creation and initialization
    numbers = [10, 20, 30, 40, 50];
    print("Original: " + numbers);
    
    // Adding elements
    numbers.push(60);
    print("After push: " + numbers);
    
    numbers.unshift(5);
    print("After unshift: " + numbers);
    
    // Removing elements
    last = numbers.pop();
    print("Popped: " + last + ", Array: " + numbers);
    
    first = numbers.shift();
    print("Shifted: " + first + ", Array: " + numbers);
    
    // Searching
    hasThirty = numbers.includes(30);
    print("Contains 30? " + hasThirty);
    
    index = numbers.indexOf(40);
    print("Index of 40: " + index);
    
    // Slicing
    subset = numbers.slice(1, 3);
    print("Slice [1:3]: " + subset);
}

// Custom array functions
$ map(arr: Array[number], fn: Function[(number), number]): Array[number] {
    result = [];
    for (item in arr) {
        result.push(fn(item));
    }
    return result;
}

$ filter(arr: Array[number], pred: Function[(number), boolean]): Array[number] {
    result = [];
    for (item in arr) {
        if (pred(item)) {
            result.push(item);
        }
    }
    return result;
}

// Usage
numbers = [1, 2, 3, 4, 5];
doubled = map(numbers, $(x) => x * 2);
evens = filter(numbers, $(x) => x % 2 == 0);
print("Doubled: " + doubled);  // [2, 4, 6, 8, 10]
print("Evens: " + evens);      // [2, 4]

Object-Oriented Programming

// Class inheritance simulation (no native inheritance yet)
class Shape {
    $ init(name: string) {
        name = name;
        type = "Shape";
    }
    
    $ describe(): string {
        return "This is a " + this.name;
    }
}

class Rectangle {
    $ init(width: number, height: number) {
        width = width;
        height = height;
        // Simulate inheritance
        this.shape = Shape("Rectangle");
    }
    
    $ area(): number {
        return this.width * this.height;
    }
    
    $ perimeter(): number {
        return 2 * (this.width + this.height);
    }
    
    $ describe(): string {
        return this.shape.describe() + 
               " with area " + this.area();
    }
}

class Circle {
    $ init(radius: number) {
        radius = radius;
        this.shape = Shape("Circle");
    }
    
    $ area(): number {
        return 3.14159 * this.radius * this.radius;
    }
    
    $ circumference(): number {
        return 2 * 3.14159 * this.radius;
    }
    
    $ describe(): string {
        return this.shape.describe() + 
               " with area " + this.area();
    }
}

// Polymorphism through duck typing
$ printShapeInfo(shape) {
    print(shape.describe());
    print("Area: " + shape.area());
}

rect = Rectangle(10, 20);
circle = Circle(5);

printShapeInfo(rect);
printShapeInfo(circle);

Error Handling Patterns

// Current error handling approach
$ safeDivide(a: number, b: number) {
    if (b == 0) {
        return {
            "success": false,
            "error": "Division by zero"
        };
    }
    return {
        "success": true,
        "value": a / b
    };
}

// Using the safe function
result = safeDivide(10, 2);
if (result["success"]) {
    print("Result: " + result["value"]);
} else {
    print("Error: " + result["error"]);
}

// Validation pattern
$ validateEmail(email: string) {
    if (email == null || email.length == 0) {
        return {"valid": false, "reason": "Email is required"};
    }
    if (!email.includes("@")) {
        return {"valid": false, "reason": "Email must contain @"};
    }
    if (!email.includes(".")) {
        return {"valid": false, "reason": "Email must contain domain"};
    }
    return {"valid": true, "email": email};
}

// Chain validation
$ processUser(userData) {
    emailCheck = validateEmail(userData["email"]);
    if (!emailCheck["valid"]) {
        print("Invalid email: " + emailCheck["reason"]);
        return false;
    }
    
    // Process valid user
    print("Processing user with email: " + emailCheck["email"]);
    return true;
}

Advanced Examples

Functional Programming Patterns

// Higher-order functions
$ compose(f: Function[(Any), Any], g: Function[(Any), Any]): Function[(Any), Any] {
    return $(x) => f(g(x));
}

$ curry(fn: Function[(Any, Any), Any]): Function[(Any), Function[(Any), Any]] {
    return $(x) => $(y) => fn(x, y);
}

// Partial application
$ add(a: number, b: number): number {
    return a + b;
}

addFive = curry(add)(5);
print(addFive(3));  // 8
print(addFive(7));  // 12

// Function composition
double = $(x) => x * 2;
addOne = $(x) => x + 1;
doubleThenAddOne = compose(addOne, double);
print(doubleThenAddOne(5));  // 11

// Reduce implementation
$ reduce(arr: Array[Any], fn: Function[(Any, Any), Any], initial: Any): Any {
    accumulator = initial;
    for (item in arr) {
        accumulator = fn(accumulator, item);
    }
    return accumulator;
}

// Sum using reduce
numbers = [1, 2, 3, 4, 5];
sum = reduce(numbers, $(acc, n) => acc + n, 0);
print("Sum: " + sum);  // 15

// Product using reduce
product = reduce(numbers, $(acc, n) => acc * n, 1);
print("Product: " + product);  // 120

Memoization

// Generic memoization wrapper
$ memoize(fn: Function[(Any), Any]): Function[(Any), Any] {
    cache = {};
    
    return $(arg) => {
        key = "" + arg;  // Convert to string for key
        
        if (cache[key] != null) {
            return cache[key];
        }
        
        result = fn(arg);
        cache[key] = result;
        return result;
    };
}

// Fibonacci with memoization
fib = memoize($(n) => {
    if (n <= 1) return n;
    return fib(n - 1) + fib(n - 2);
});

// Fast even for large numbers
print(fib(40));  // Instant result

// Custom memoization for multiple arguments
$ memoize2(fn: Function[(Any, Any), Any]): Function[(Any, Any), Any] {
    cache = {};
    
    return $(a, b) => {
        key = a + "," + b;
        
        if (cache[key] != null) {
            return cache[key];
        }
        
        result = fn(a, b);
        cache[key] = result;
        return result;
    };
}

State Management

// Simple state manager
class StateManager {
    $ init() {
        state = {};
        listeners = [];
    }
    
    $ get(key: string) {
        return this.state[key];
    }
    
    $ set(key: string, value: Any) {
        oldValue = this.state[key];
        this.state[key] = value;
        
        // Notify listeners
        for (listener in this.listeners) {
            listener(key, oldValue, value);
        }
    }
    
    $ subscribe(listener: Function[(string, Any, Any), void]) {
        this.listeners.push(listener);
    }
    
    $ getState() {
        // Return copy of state
        copy = {};
        for (key in this.state) {
            copy[key] = this.state[key];
        }
        return copy;
    }
}

// Usage
store = StateManager();

// Subscribe to changes
store.subscribe($(key, oldVal, newVal) => {
    print("State changed: " + key + " from " + oldVal + " to " + newVal);
});

// Modify state
store.set("user", "Alice");
store.set("score", 100);
store.set("score", 150);

print("Current state: " + store.getState());

Real-World Applications

CSV Parser

// Simple CSV parser
$ parseCSV(content: string, delimiter: string): Array[Array[string]] {
    lines = content.split("\n");  // Assuming split is available
    result = [];
    
    for (line in lines) {
        if (line.length > 0) {
            // Simple parsing (doesn't handle quoted fields)
            fields = [];
            current = "";
            
            for (char in line) {
                if (char == delimiter) {
                    fields.push(current);
                    current = "";
                } else {
                    current = current + char;
                }
            }
            
            if (current.length > 0) {
                fields.push(current);
            }
            
            result.push(fields);
        }
    }
    
    return result;
}

// Usage
csvData = "name,age,city\nAlice,30,Seattle\nBob,25,Portland";
parsed = parseCSV(csvData, ",");

// Process as table
headers = parsed[0];
for (i = 1; i < parsed.length; i += 1) {
    row = parsed[i];
    record = {};
    for (j = 0; j < headers.length; j += 1) {
        record[headers[j]] = row[j];
    }
    print("Record: " + record);
}

Simple HTTP Server Response Builder

// HTTP response builder
class HTTPResponse {
    $ init() {
        statusCode = 200;
        headers = {};
        body = "";
    }
    
    $ status(code: number) {
        this.statusCode = code;
        return this;  // Fluent interface
    }
    
    $ header(name: string, value: string) {
        this.headers[name] = value;
        return this;
    }
    
    $ json(data) {
        this.header("Content-Type", "application/json");
        // Simple JSON encoding (real implementation would be more complex)
        this.body = this.encodeJSON(data);
        return this;
    }
    
    $ text(content: string) {
        this.header("Content-Type", "text/plain");
        this.body = content;
        return this;
    }
    
    $ encodeJSON(data) {
        if (data == null) return "null";
        if (typeof(data) == "string") return "\"" + data + "\"";
        if (typeof(data) == "number") return "" + data;
        if (typeof(data) == "boolean") return data ? "true" : "false";
        
        // Simple object encoding
        if (typeof(data) == "object") {
            result = "{";
            first = true;
            for (key in data) {
                if (!first) result = result + ",";
                result = result + "\"" + key + "\":" + this.encodeJSON(data[key]);
                first = false;
            }
            return result + "}";
        }
        
        return "null";
    }
    
    $ build(): string {
        response = "HTTP/1.1 " + this.statusCode + " OK\n";
        for (header in this.headers) {
            response = response + header + ": " + this.headers[header] + "\n";
        }
        response = response + "\n" + this.body;
        return response;
    }
}

// Usage
response = HTTPResponse()
    .status(200)
    .json({
        "success": true,
        "user": "Alice",
        "score": 150
    });

print(response.build());

Task Queue

// Simple task queue implementation
class TaskQueue {
    $ init() {
        tasks = [];
        running = false;
    }
    
    $ add(task: Function[(), void]) {
        this.tasks.push(task);
        if (!this.running) {
            this.process();
        }
    }
    
    $ process() {
        this.running = true;
        
        while (this.tasks.length > 0) {
            task = this.tasks.shift();
            
            // Execute task with error handling
            try {
                task();
            } catch (e) {
                print("Task failed: " + e);
            }
        }
        
        this.running = false;
    }
}

// Usage
queue = TaskQueue();

queue.add($() => {
    print("Task 1: Starting download");
    // Simulate work
    for (i = 0; i < 1000000; i += 1) { }
    print("Task 1: Download complete");
});

queue.add($() => {
    print("Task 2: Processing data");
    // Simulate work
    for (i = 0; i < 500000; i += 1) { }
    print("Task 2: Processing complete");
});

queue.add($() => {
    print("Task 3: Saving results");
    print("Task 3: Save complete");
});

Algorithm Implementations

Sorting Algorithms

// Bubble Sort
$ bubbleSort(arr: Array[number]): Array[number] {
    n = arr.length;
    result = arr.slice(0);  // Copy array
    
    for (i = 0; i < n - 1; i += 1) {
        for (j = 0; j < n - i - 1; j += 1) {
            if (result[j] > result[j + 1]) {
                // Swap
                temp = result[j];
                result[j] = result[j + 1];
                result[j + 1] = temp;
            }
        }
    }
    
    return result;
}

// Quick Sort
$ quickSort(arr: Array[number]): Array[number] {
    if (arr.length <= 1) return arr;
    
    pivot = arr[0];
    left = [];
    right = [];
    
    for (i = 1; i < arr.length; i += 1) {
        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }
    
    // Recursively sort and combine
    sortedLeft = quickSort(left);
    sortedRight = quickSort(right);
    
    result = [];
    for (item in sortedLeft) result.push(item);
    result.push(pivot);
    for (item in sortedRight) result.push(item);
    
    return result;
}

// Test sorting
data = [64, 34, 25, 12, 22, 11, 90];
print("Original: " + data);
print("Bubble sorted: " + bubbleSort(data));
print("Quick sorted: " + quickSort(data));

Search Algorithms

// Binary Search
$ binarySearch(arr: Array[number], target: number): number {
    left = 0;
    right = arr.length - 1;
    
    while (left <= right) {
        mid = left + (right - left) / 2;
        mid = Math.floor(mid);  // Assuming Math.floor exists
        
        if (arr[mid] == target) {
            return mid;
        }
        
        if (arr[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    
    return -1;  // Not found
}

// Depth-First Search on a graph
$ dfs(graph: Object, start: string, visited: Object) {
    if (visited == null) visited = {};
    
    visited[start] = true;
    print("Visiting: " + start);
    
    neighbors = graph[start];
    if (neighbors != null) {
        for (neighbor in neighbors) {
            if (!visited[neighbor]) {
                dfs(graph, neighbor, visited);
            }
        }
    }
}

// Graph representation
graph = {
    "A": ["B", "C"],
    "B": ["A", "D", "E"],
    "C": ["A", "F"],
    "D": ["B"],
    "E": ["B", "F"],
    "F": ["C", "E"]
};

print("DFS traversal:");
dfs(graph, "A", null);

Dynamic Programming

// Longest Common Subsequence
$ lcs(str1: string, str2: string): number {
    m = str1.length;
    n = str2.length;
    
    // Create 2D array for DP table
    dp = [];
    for (i = 0; i <= m; i += 1) {
        row = [];
        for (j = 0; j <= n; j += 1) {
            row.push(0);
        }
        dp.push(row);
    }
    
    // Fill DP table
    for (i = 1; i <= m; i += 1) {
        for (j = 1; j <= n; j += 1) {
            if (str1[i-1] == str2[j-1]) {
                dp[i][j] = dp[i-1][j-1] + 1;
            } else {
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
            }
        }
    }
    
    return dp[m][n];
}

$ max(a: number, b: number): number {
    return a > b ? a : b;
}

// Test LCS
print("LCS of 'ABCDGH' and 'AEDFHR': " + lcs("ABCDGH", "AEDFHR"));  // 3 (ADH)

Design Patterns

Observer Pattern

// Observer pattern implementation
class Subject {
    $ init() {
        observers = [];
        state = null;
    }
    
    $ attach(observer) {
        this.observers.push(observer);
    }
    
    $ detach(observer) {
        newObservers = [];
        for (obs in this.observers) {
            if (obs != observer) {
                newObservers.push(obs);
            }
        }
        this.observers = newObservers;
    }
    
    $ notify() {
        for (observer in this.observers) {
            observer.update(this.state);
        }
    }
    
    $ setState(newState) {
        this.state = newState;
        this.notify();
    }
}

class Observer {
    $ init(name: string) {
        name = name;
    }
    
    $ update(state) {
        print(this.name + " received update: " + state);
    }
}

// Usage
subject = Subject();
observer1 = Observer("Observer1");
observer2 = Observer("Observer2");

subject.attach(observer1);
subject.attach(observer2);

subject.setState("State A");
subject.setState("State B");

subject.detach(observer1);
subject.setState("State C");

Factory Pattern

// Factory pattern for creating different types of vehicles
class Vehicle {
    $ init(type: string) {
        type = type;
    }
    
    $ describe(): string {
        return "This is a " + this.type;
    }
}

class Car {
    $ init(model: string) {
        model = model;
        this.vehicle = Vehicle("Car");
    }
    
    $ drive() {
        print("Driving the " + this.model);
    }
}

class Bike {
    $ init(brand: string) {
        brand = brand;
        this.vehicle = Vehicle("Bike");
    }
    
    $ ride() {
        print("Riding the " + this.brand);
    }
}

class VehicleFactory {
    $ create(type: string, name: string) {
        if (type == "car") {
            return Car(name);
        } else if (type == "bike") {
            return Bike(name);
        } else {
            print("Unknown vehicle type: " + type);
            return null;
        }
    }
}

// Usage
factory = VehicleFactory();
myCar = factory.create("car", "Toyota");
myBike = factory.create("bike", "Trek");

if (myCar != null) myCar.drive();
if (myBike != null) myBike.ride();

Tutorial Projects

Project 1: Todo List Application

// Complete Todo List application
class Todo {
    $ init(id: number, text: string) {
        id = id;
        text = text;
        completed = false;
        createdAt = clock();
    }
    
    $ toggle() {
        this.completed = !this.completed;
    }
    
    $ toString(): string {
        status = this.completed ? "[X]" : "[ ]";
        return status + " " + this.text;
    }
}

class TodoList {
    $ init() {
        todos = [];
        nextId = 1;
    }
    
    $ add(text: string): Todo {
        todo = Todo(this.nextId, text);
        this.nextId += 1;
        this.todos.push(todo);
        return todo;
    }
    
    $ remove(id: number): boolean {
        newTodos = [];
        found = false;
        
        for (todo in this.todos) {
            if (todo.id != id) {
                newTodos.push(todo);
            } else {
                found = true;
            }
        }
        
        this.todos = newTodos;
        return found;
    }
    
    $ toggle(id: number): boolean {
        for (todo in this.todos) {
            if (todo.id == id) {
                todo.toggle();
                return true;
            }
        }
        return false;
    }
    
    $ list(showCompleted: boolean) {
        print("\n=== Todo List ===");
        for (todo in this.todos) {
            if (showCompleted || !todo.completed) {
                print(todo.id + ": " + todo.toString());
            }
        }
        print("================\n");
    }
    
    $ getStats() {
        total = this.todos.length;
        completed = 0;
        
        for (todo in this.todos) {
            if (todo.completed) {
                completed += 1;
            }
        }
        
        return {
            "total": total,
            "completed": completed,
            "pending": total - completed
        };
    }
}

// Interactive todo app
todoList = TodoList();

// Add some todos
todoList.add("Learn ThornLang");
todoList.add("Build a project");
todoList.add("Contribute to ThornLang");

// Display list
todoList.list(true);

// Toggle first item
todoList.toggle(1);
print("Toggled item 1");

// Show updated list
todoList.list(true);

// Show statistics
stats = todoList.getStats();
print("Stats: Total=" + stats["total"] + 
      ", Completed=" + stats["completed"] + 
      ", Pending=" + stats["pending"]);

Project 2: Simple Calculator

// Calculator with expression evaluation
class Calculator {
    $ init() {
        operators = {
            "+": $(a, b) => a + b,
            "-": $(a, b) => a - b,
            "*": $(a, b) => a * b,
            "/": $(a, b) => b != 0 ? a / b : null,
            "^": $(a, b) => a ** b
        };
    }
    
    $ evaluate(expression: string): number {
        // Simple expression parser (only handles binary operations)
        tokens = this.tokenize(expression);
        
        if (tokens.length != 3) {
            print("Error: Expression must be 'number operator number'");
            return null;
        }
        
        left = this.parseNumber(tokens[0]);
        operator = tokens[1];
        right = this.parseNumber(tokens[2]);
        
        if (left == null || right == null) {
            print("Error: Invalid numbers");
            return null;
        }
        
        if (this.operators[operator] == null) {
            print("Error: Unknown operator '" + operator + "'");
            return null;
        }
        
        result = this.operators[operator](left, right);
        if (result == null) {
            print("Error: Division by zero");
            return null;
        }
        
        return result;
    }
    
    $ tokenize(expression: string): Array[string] {
        tokens = [];
        current = "";
        
        for (char in expression) {
            if (char == " ") {
                if (current.length > 0) {
                    tokens.push(current);
                    current = "";
                }
            } else {
                current = current + char;
            }
        }
        
        if (current.length > 0) {
            tokens.push(current);
        }
        
        return tokens;
    }
    
    $ parseNumber(str: string): number {
        // Simple number parsing
        result = 0;
        decimal = false;
        decimalPlace = 0.1;
        
        for (char in str) {
            if (char == ".") {
                decimal = true;
            } else if (char >= "0" && char <= "9") {
                digit = char.charCodeAt(0) - "0".charCodeAt(0);
                if (!decimal) {
                    result = result * 10 + digit;
                } else {
                    result = result + digit * decimalPlace;
                    decimalPlace = decimalPlace / 10;
                }
            } else {
                return null;  // Invalid character
            }
        }
        
        return result;
    }
}

// Calculator usage
calc = Calculator();

// Test expressions
expressions = [
    "10 + 5",
    "20 - 8",
    "6 * 7",
    "15 / 3",
    "2 ^ 8",
    "10 / 0"  // Division by zero
];

for (expr in expressions) {
    result = calc.evaluate(expr);
    if (result != null) {
        print(expr + " = " + result);
    }
}

Summary

These examples demonstrate:

  1. Basic Syntax - Variables, functions, control flow
  2. Data Structures - Arrays, objects, classes
  3. Algorithms - Sorting, searching, dynamic programming
  4. Design Patterns - Observer, Factory, State management
  5. Real Applications - Todo lists, calculators, parsers

Start with the basic examples and work your way up. Each example builds on previous concepts while introducing new ThornLang features.

See Also