Chapter 14: Standard Library
What's Included
Wyn's standard library gives you the tools to build real applications without external dependencies. It's not as large as Python's or as comprehensive as Rust's, but it covers the essentials.
This chapter is a tour of what's available. For complete API documentation, see Appendix B.
String Operations
You've seen basic string methods. Here's the full set:
Inspection
var text = "Hello, World!"
text.len() // 13
text.is_empty() // false
text.contains("World") // true
text.starts_with("Hello") // true
text.ends_with("!") // trueTransformation
var text = " Hello "
text.trim() // "Hello"
text.trim_left() // "Hello "
text.trim_right() // " Hello"
text.upper() // " HELLO "
text.lower() // " hello "
text.reverse() // " olleH "Searching
Index methods return the position, or -1 if not found:
var text = "Hello, World!"
text.index_of("o") // 4
text.last_index_of("o") // 8
text.index_of("xyz") // -1Splitting and Joining
var text = "apple,banana,cherry"
var parts = text.split(",") // ["apple", "banana", "cherry"]
var joined = parts.join(" - ") // "apple - banana - cherry"Substring
var text = "Hello, World!"
text.substring(0, 5) // "Hello"
text.substring(7) // "World!"Replacement
var text = "Hello, World!"
text.replace("World", "Wyn") // "Hello, Wyn!"
text.replace_all("l", "L") // "HeLLo, WorLd!"Parsing
var num_str = "42"
var float_str = "3.14"
num_str.to_int() // 42
float_str.to_float() // 3.14
"abc".to_int() // 0 (unparseable -> 0)Unparseable strings convert to 0-validate with is_numeric() first when you need to tell "0" apart from garbage.
File I/O
File operations live in the File namespace. File::read returns the contents as a string (empty if the file is missing), so guard with File::exists:
Reading Files
fn main() -> int {
if (not File::exists("data.txt")) {
print("data.txt not found")
return 1
}
var contents = File::read("data.txt")
print("File contents:")
print(contents)
return 0
}Writing Files
fn main() -> int {
var data = "Hello, file!"
var ok = File::write("output.txt", data)
if (ok == 1) {
print("File written")
} else {
print("Error writing file")
}
return 0
}File::write returns 1 on success, 0 on failure.
Appending to Files
fn main() -> int {
var ok = File::append("log.txt", "New log entry\n")
if (ok == 1) {
print("Appended")
} else {
print("Error appending")
}
return 0
}File Metadata
fn main() -> int {
if (File::exists("data.txt")) {
print("File exists")
var size = File::size("data.txt")
print("Size: ${size}")
}
return 0
}Directory Operations
fn main() -> int {
// List files in directory
var files = Dir::list(".")
for (var i = 0; i < files.len(); i = i + 1) {
print(files[i])
}
// Create directory
Dir::create("new_folder")
// Remove directory
Dir::remove("old_folder")
return 0
}Networking
HTTP Client
Http.get returns the response body as a string (empty on failure):
fn main() -> int {
var body = Http.get("https://api.example.com/data")
if (body.len() > 0) {
print("Body: " + body)
} else {
print("Request failed")
}
return 0
}HTTP POST
fn main() -> int {
var data = {"name": "Alice", "age": "30"}
var body = Http.post("https://api.example.com/users", JSON::stringify(data))
print("Created: " + body)
return 0
}HTTP Server
Http.serve(port) starts a server; Http.accept blocks until a request arrives and returns it as a method|path|headers|fd string:
fn main() -> int {
var server = Http.serve(8080)
print("Server running on http://localhost:8080")
while (true) {
var req = Http.accept(server)
var path = req.split_at("|", 1)
var fd = req.split_at("|", 3).to_int()
if (path == "/") {
Http.respond(fd, 200, "text/plain", "Hello, World!")
} else {
Http.respond(fd, 404, "text/plain", "Not Found")
}
}
return 0
}JSON
Parsing JSON
fn main() -> int {
var json_str = "{\"name\": \"Alice\", \"age\": 30}"
var json = json_parse(json_str)
print(json["name"]) // "Alice"
print(json["age"]) // 30
return 0
}Generating JSON
fn main() -> int {
var data = {
"name": "Alice",
"role": "admin"
}
var json_str = JSON::stringify(data)
print(json_str) // {"name":"Alice","role":"admin"}
return 0
}Time and Date
Current Time
fn main() -> int {
var now = Time::now()
print("Current timestamp: ${now}")
return 0
}Formatting Time
fn main() -> int {
var now = Time::now()
var formatted = Time::format(now, "%Y-%m-%d %H:%M:%S")
print(formatted) // "2026-02-09 13:00:00"
return 0
}Time Arithmetic
Timestamps are seconds since the epoch-plain integers, so plain arithmetic works:
fn main() -> int {
var now = Time::now()
var tomorrow = now + 86400 // Add 24 hours (in seconds)
var yesterday = now - 86400
print(tomorrow - yesterday) // 172800
return 0
}Sleep
fn main() -> int {
print("Starting...")
sleep(1000) // Sleep for 1000ms (1 second)
print("Done!")
return 0
}System Operations
Command-Line Arguments
fn main() -> int {
var args = System::args()
print("Program name: " + args[0])
for (var i = 1; i < args.len(); i = i + 1) {
print("Arg ${i}: ${args[i]}")
}
return 0
}Environment Variables
Env::get returns the value, or an empty string if the variable isn't set:
fn main() -> int {
var home = Env::get("HOME")
if (home.len() > 0) {
print("Home: " + home)
} else {
print("HOME not set")
}
Env::set("MY_VAR", "my_value")
return 0
}Process Execution
System::exec returns the command's output; System::exec_code returns its exit code:
fn main() -> int {
var output = System::exec("ls -la")
print("Output: " + output)
var code = System::exec_code("ls -la")
print("Exit code: ${code}")
return 0
}Exit Codes
fn main() -> int {
var fatal = File::exists("panic.flag")
if (fatal) {
print("Fatal error")
return 1 // Non-zero indicates error
}
return 0 // Success
}Math Operations
Basic Math
fn main() -> int {
var x = 16.0
print(Math::sqrt(x)) // 4.0
print(Math::pow(2.0, 8.0)) // 256.0
print(abs(-42)) // 42
print(min(5, 3)) // 3
print(max(5, 3)) // 5
return 0
}Trigonometry
fn main() -> int {
print(Math::sin(Math::PI / 2.0)) // 1.0
print(Math::cos(0.0)) // 1.0
print(Math::tan(Math::PI / 4.0)) // 1.0
return 0
}Random Numbers
fn main() -> int {
// Random integer between 0 and 99
var rand_int = random_int(0, 100)
print(rand_int)
// Random float between 0.0 and 1.0
var rand_float = random_float()
print(rand_float)
return 0
}Putting It Together: Real Examples
Log File Parser
fn count_errors(path: string) -> Result<int, string> {
if (not File::exists(path)) {
return Err("file not found: " + path)
}
var contents = File::read(path)
var lines = contents.split("\n")
var errors = 0
for (var i = 0; i < lines.len(); i = i + 1) {
if (lines[i].contains("ERROR")) {
errors = errors + 1
}
}
return Ok(errors)
}
fn main() -> int {
var result = count_errors("app.log")
match result {
Ok(count) => print("Errors: ${count}"),
Err(msg) => print("Error: " + msg)
}
return 0
}REST API Client
struct User {
id: int,
name: string,
email: string
}
fn fetch_user(id: int) -> Result<User, string> {
var url = "https://api.example.com/users/${id}"
var body = Http.get(url)
if (body.len() == 0) {
return Err("request failed")
}
var json = json_parse(body)
var user = User {
id: json["id"],
name: json["name"],
email: json["email"]
}
return Ok(user)
}
fn main() -> int {
var result = fetch_user(1)
match result {
Ok(user) => {
print("User: " + user.name)
print("Email: " + user.email)
},
Err(msg) => print("Error: " + msg)
}
return 0
}Configuration Manager
struct Config {
host: string,
port: int
}
fn load_config(path: string) -> Result<Config, string> {
if (not File::exists(path)) {
return Err("config file not found")
}
var contents = File::read(path)
var json = json_parse(contents)
var config = Config {
host: json["host"],
port: json["port"]
}
return Ok(config)
}
fn save_config(path: string, config: Config) -> int {
var data = {
"host": config.host,
"port": config.port.to_string()
}
return File::write(path, JSON::stringify(data))
}
fn main() -> int {
var config = load_config("config.json")
match config {
Ok(cfg) => {
print("Host: " + cfg.host)
print("Port: ${cfg.port}")
},
Err(msg) => {
print("Using defaults")
var default_cfg = Config {
host: "localhost",
port: 8080
}
save_config("config.json", default_cfg)
}
}
return 0
}What You've Learned
Wyn's standard library covers strings, files, networking, JSON, time, and system operations. It's enough to build real applications without external dependencies.
I/O primitives signal failure with simple values-empty strings, 0/1 status codes-so guard with checks like File::exists and wrap them in your own Result-returning functions for clean error handling with match and ?.
The library is designed for simplicity. Functions do one thing well. Types are straightforward. Error messages are clear.
For complete API documentation, see Appendix B.
Data Persistence
Save and load HashMaps as JSON files:
fn main() -> int {
// Save state
var data = { "name": "Alice", "score": "100" }
Data.save("state.json", data)
// Load state (returns empty HashMap if file missing)
var loaded = Data.load("state.json")
println(loaded.get("name")) // Alice
println(loaded.get("score")) // 100
return 0
}Exercises
File processor: Read a text file, count words, lines, and characters. Write results to another file.
HTTP client: Fetch data from a public API, parse the JSON, and display specific fields.
Log analyzer: Parse a log file, count different log levels (INFO, WARN, ERROR), and generate a summary.
Config manager: Create a program that loads configuration from a JSON file, with fallback to defaults if the file doesn't exist.
Simple web server: Create an HTTP server that serves static files from a directory.
Command-line tool: Build a CLI tool that accepts arguments and performs different actions based on them.
Data pipeline: Read CSV data, transform it, and write JSON output.