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
- Intermediate Examples
- Advanced Examples
- Real-World Applications
- Algorithm Implementations
- Design Patterns
- Tutorial Projects
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:
- Basic Syntax - Variables, functions, control flow
- Data Structures - Arrays, objects, classes
- Algorithms - Sorting, searching, dynamic programming
- Design Patterns - Observer, Factory, State management
- 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
- Language Reference - Complete syntax guide
- Type System - Understanding types
- Performance Guide - Writing efficient code
- Built-in Functions - Available functions