Idiomatic Patterns
Idiomatic Patterns
Pattern 1: Immutable Update for Structs
Since Thagore struct methods return new instances rather than mutating in place, use the reassignment pattern:
struct Counter: value: i32
func increment(self: Counter) -> Counter: return Counter(self.value + 1)
func main() -> i32: let c = Counter(0) c = increment(c) # Reassign to capture the new value c = increment(c) print(c.value) # Output: 2 return 0Pattern 2: Error Handling with Return Codes
Use i32 return codes for error signaling:
import fs
func process_config(path: String) -> i32: if (fs.exists(path) == 0): print("Error: config not found") return 1 let content = fs.read_text(path) if (content == ""): print("Error: empty config") return 2 print("Config loaded: " + content) return 0
func main() -> i32: let rc = process_config("config.txt") if (rc != 0): print("Failed with code:") print(rc) return rcPattern 3: Builder Pattern
Build complex objects step-by-step:
import "std/string.tg" as sstr
func build_html_list(items: [String; 3]) -> String: let sb = sstr.builder_new() sb = sstr.append(sb, "<ul>") let i = 0 while (i < 3): sb = sstr.append(sb, "<li>") sb = sstr.append(sb, items[i]) sb = sstr.append(sb, "</li>") i = i + 1 sb = sstr.append(sb, "</ul>") return sstr.to_string(sb)Pattern 4: CLI Argument Parsing
Build command-line tools using the env module:
import env
func main() -> i32: let argc = env.count() if (argc < 2): print("Usage: mytool <command> [options]") return 1
let cmd = env.get(1) if (cmd == "hello"): print("Hello!") return 0 if (cmd == "version"): print("mytool v1.0.0") return 0
print("Unknown command: " + cmd) return 1Pattern 5: Resource Cleanup
Use explicit cleanup calls (or defer when available):
import fs
func process_file(path: String) -> i32: let handle = fs.open_read(path) # ... process data ... let data = fs.read_bytes(handle, 1024) print(data) fs.close(handle) # Always close the handle return 0Pattern 6: Struct as Namespace
Group related functions using a struct with impl:
struct Math: dummy: i32
impl Math: func max(self, a: i32, b: i32) -> i32: if (a > b): return a return b
func min(self, a: i32, b: i32) -> i32: if (a < b): return a return b
func abs(self, x: i32) -> i32: if (x < 0): return 0 - x return xPattern 7: FFI Wrapper
Wrap C functions in a safe Thagore API:
extern func sqrtf(x: f32) -> f32extern func powf(base: f32, exp: f32) -> f32extern func sinf(x: f32) -> f32extern func cosf(x: f32) -> f32
func sqrt(x: f32) -> f32: if (x < 0.0): return 0.0 # Guard against negative input return sqrtf(x)
func distance(x1: f32, y1: f32, x2: f32, y2: f32) -> f32: let dx = x2 - x1 let dy = y2 - y1 return sqrt(dx * dx + dy * dy)Pattern 8: Test Organization
Structure tests with clear names and expected outputs:
func test_addition() -> i32: let result = 2 + 3 if (result != 5): print("FAIL: test_addition") return 1 print("PASS: test_addition") return 0
func test_string_concat() -> i32: let s = "a" + "b" if (s != "ab"): print("FAIL: test_string_concat") return 1 print("PASS: test_string_concat") return 0
func main() -> i32: let failures = 0 failures = failures + test_addition() failures = failures + test_string_concat() if (failures > 0): print("Some tests failed!") else: print("All tests passed!") return failuresPattern 9: Process Orchestration
Chain shell commands for automation:
import processimport fs
func build_and_test(source: String) -> i32: let rc = process.run("thagore build " + source + " -o test_binary.exe") if (rc != 0): print("Build failed!") return 1
rc = process.run(".\\test_binary.exe") if (rc != 0): print("Test failed!") return 2
print("Build and test passed!") return 0