fn main() x = sleep(1000, 10) y = sleep(1000, 20) print(x + y) # Automatically waits when values are needed
No await keyword. Async values resolve automatically when you need them. Write synchronous-looking code that runs asynchronously.
HTTP client and web server built into the standard library. Create APIs and services with minimal boilerplate.
Python-like syntax with indentation-based blocks. Easy to read, easy to write, easy to maintain.
All I/O operations are non-blocking by default. Node.js-style runtime behavior with better ergonomics.
Built-in spawn, all, race, timeout, and cancel. Powerful concurrency without the complexity.
File I/O, JSON processing, HTTP client/server, and async primitives all in the standard library.
Built-in template strings with {{ variable }} syntax. Return HTML from handlers with automatic variable interpolation.
Optional type hints (str, int, float, Json) with automatic runtime validation and coercion in function parameters.
Python-style decorators for web routing. Use @app.get("/path") or @route.post("/api") to define endpoints declaratively.
const x = await sleep(1000, 10); const y = await sleep(1000, 20); console.log(x + y);
Sequential execution, must remember await
x = await sleep(1, 10) y = await sleep(1, 20) print(x + y)
Requires async/await keywords everywhere
x = sleep(1000, 10) y = sleep(1000, 20) print(x + y)
Concurrent execution, no await needed
app = WebApp() server = WebServer() @app.get("/") fn index() return "Hello world" @app.get("/hello/<name>") fn hello(name) return "Hello {{ name }}" server.run(app)
fn work(n) sleep(500, n * 2) jobs = [spawn(work(2)), spawn(work(5)), spawn(work(7))] results = all(jobs) print(results) # [4, 10, 14]
http = Http() resp = http.get("https://api.example.com/data") data = resp.json() print(data["results"])
app = WebApp() server = WebServer() @app.post("/users") fn create_user(data: Json) return {"id": 123, "name": data["name"]} server.run(app)
count = 0 count =+ 5 # count is now 5 count =- 2 # count is now 3 print(count)
Single-file interpreter with AST-based evaluation. Uses Tokio for async runtime, ensuring robust concurrency.
Web server built on Axum framework with automatic JSON responses, path parameters, query strings, and request body handling.
Implicit async through Value::Deferred. Operations return immediately; resolution happens automatically when values are needed.
4 spaces per level, no tabs. Clean syntax without semicolons or braces, similar to Python but with async superpowers.
@app.post("/api/users/<id>") fn update_user(id: int, data: Json, role: str = "user") # id comes from path parameter # data is the JSON request body # role comes from query string (defaults to "user") return {"updated": id, "role": role}
Relay is a single-file Rust interpreter. Dependencies: tokio, serde, serde_json, reqwest, axum, tower, tower-http, html-escape, indexmap, async-recursion, thiserror, anyhow
Default bind: 127.0.0.1:3000. Override with environment variable:
print(value) # Output to console str(x) # Convert to string int(x) # Convert to integer float(x) # Convert to float
sleep(ms, value) # Non-blocking delay, returns value after ms spawn(expr) # Spawn task, returns Task handle all([tasks]) # Wait for all tasks, return list of results race([tasks]) # Return first completed task result timeout(expr, ms) # Timeout an expression after ms cancel(task) # Cancel a running task task.join() # Wait for task completion deferred.resolve() # Force resolution of deferred value
read_file(path) # Read file as string save_file(content, path) # Write string to file read_json(path) # Read and parse JSON file save_json(data, path) # Serialize and save JSON
http = Http() resp = http.get(url) resp = http.post(url, data) # Response object members: resp.status # HTTP status code (int) resp.text # Response body as string resp.json() # Parse response as JSON
app = WebApp() route = app.route() # Optional: get route handle server = WebServer() # Decorator routing (use @app or @route): @app.get(path) @app.post(path) @route.get(path) @route.post(path) # Manual response control: Response(body, status=200, content_type="text/plain") # Start server (bind address via RELAY_BIND env var): server.run(app)