Ruff is a purpose-built, correctness-first execution language designed for tooling, automation, and AI-assisted development.
Status: v0.8.0 (Released January 2026) - Async/Await & Modern Concurrency! β‘ Previous: v0.7.0 (January 2026) - Core Language Complete
Quick Links: Installation β’ Getting Started β’ REPL β’ Examples β’ Features β’ Changelog β’ Roadmap
- Interpreter Modularization (Phase 3 Complete) π―
- Successfully refactored 14,802-line monolithic interpreter into focused modules
- Extracted 249 native functions into 13 category-based modules
- Reduced main interpreter file by 68.5% (14,071 β 4,426 lines)
- Created dispatcher pattern for efficient function routing
- All 198 tests passing with zero regressions
- Module architecture: math, strings, collections, type_ops, filesystem, system, http, concurrency, io
- Stub modules ready for future expansion: json, crypto, database, network
- Benefits: better code organization, easier maintenance, improved IDE support, parallel development
- See
ROADMAP.mdfor complete Phase 3 details and future work
-
Async/Await β‘
- Full asynchronous programming with Promise-based concurrency
- Async function syntax:
async func name() { ... } - Await expression:
result := await promise - Thread-based execution for true concurrency
- Example:
# Async function declaration async func fetch_user(id) { let data := simulate_api_call(id) return {"id": id, "name": "User ${id}", "data": data} } # Call async function and await result let promise := fetch_user(42) let user := await promise print("Got user: ${user.name}") # Concurrent execution - start multiple async operations let p1 := fetch_user(1) let p2 := fetch_user(2) let p3 := fetch_user(3) # Wait for all results let u1 := await p1 let u2 := await p2 let u3 := await p3 print("Fetched ${u1.name}, ${u2.name}, ${u3.name}") - Thread-safe architecture: Complete Arc<Mutex<>> refactor throughout codebase
- Compatible with existing concurrency features (spawn blocks, channels)
- See
examples/async_comprehensive_demo.rufffor 27 test scenarios
-
Iterators & Method Chaining π
- Lazy evaluation with iterator methods:
.filter(),.map(),.take(),.collect() - Method chaining for data processing pipelines without intermediate arrays
- Memory-efficient iteration over collections
- Example:
# Filter, transform, and limit in one expression numbers := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] result := numbers .filter(func(n) { return n % 2 == 0 }) # Even numbers only .map(func(n) { return n * n }) # Square them .take(5) # First 5 results .collect() # Execute and collect # Result: [4, 16, 36, 64, 100] # Practical use case: data processing pipeline passing_curved := scores .filter(func(s) { return s >= 60 }) # Filter passing .map(func(s) { return s + 5 }) # Apply curve .take(5) # Top 5 .collect() - Generator functions with
func*andyieldfor lazy sequence generation:func* fibonacci() { let a := 0 let b := 1 loop { yield a let temp := a a := b b := temp + b } } # Get first 10 fibonacci numbers count := 0 for n in fibonacci() { print(n) count := count + 1 if count >= 10 { break } } - See
examples/iterators_comprehensive.rufffor 8 different usage patterns
- Lazy evaluation with iterator methods:
-
Built-in Testing Framework π§ͺ
- Native testing support with
test,test_setup,test_teardown, andtest_groupsyntax - Four assertion functions for comprehensive test coverage:
assert_equal(actual, expected)- Compare values (Int, Float, Str, Bool, Null, Array, Dict)assert_true(value)- Assert boolean is trueassert_false(value)- Assert boolean is falseassert_contains(collection, item)- Check array/string/dict membership
- Isolated test environments with setup/teardown support
- Test runner with colored output and timing information
- CLI command:
ruff test-run <file> [--verbose] - Example:
test_setup { # Runs before each test test_data := [] } test "array operations work correctly" { numbers := [1, 2, 3, 4, 5] assert_equal(len(numbers), 5) assert_contains(numbers, 3) assert_true(len(numbers) > 0) } test "string operations" { text := "Hello, Ruff!" assert_equal(len(text), 12) assert_false(len(text) == 0) } test_teardown { # Cleanup after each test test_data := [] } - See
examples/testing_demo.rufffor 27 test examples and best practices - Comprehensive test suite in
tests/testing_framework.ruffwith 25 tests
- Native testing support with
-
VM Native Function Integration π
- All 180+ built-in functions now work in bytecode VM mode
- Zero code duplication: VM delegates to interpreter implementation
- Complete support for math, string, array, dict, file I/O, HTTP, database, compression, crypto, process management, OS, path, and more
- Test suite validates all function categories work correctly
- Example:
# All these work in VM mode (run with --vm flag): print("Math:", sqrt(144), pow(2, 10)) let data := http_get("api.example.com/data") let parsed := parse_json(data.body) let hash := sha256(to_json(parsed)) write_file("output.txt", hash) - Known limitation: VM loop execution needs fixing before performance benchmarks can run
- See
tests/vm_native_functions_test.rufffor comprehensive test coverage
-
Standard Library Expansion π¦
- Comprehensive compression, hashing, process management, OS interaction, and path manipulation functions
- Compression: Create and extract ZIP archives (
zip_create,zip_add_file,zip_add_dir,zip_close,unzip) - Hashing: SHA-256, MD5 for data integrity (
sha256,md5,md5_file) - Password Security: Bcrypt password hashing (
hash_password,verify_password) - Process Management: Execute commands and pipe operations (
spawn_process,pipe_commands) - OS Module: Operating system interaction (
os_getcwd,os_chdir,os_rmdir,os_environ) - Path Module: Cross-platform path manipulation (
path_join,path_absolute,path_is_dir,path_is_file,path_extension) - Example:
# Create backup archive archive := zip_create("backup.zip") zip_add_dir(archive, "documents/") zip_close(archive) # Verify file integrity let hash := md5_file("important.pdf") # Secure password storage let hashed := hash_password("user_password") let valid := verify_password("user_password", hashed) # Execute system commands let result := spawn_process(["ls", "-la"]) print(result.stdout) # Pipe commands together let errors := pipe_commands([ ["cat", "server.log"], ["grep", "ERROR"], ["wc", "-l"] ]) # Directory navigation let original := os_getcwd() os_chdir("workspace") # Do work... os_chdir(original) # Cross-platform path handling let config := path_join("home", "user", "config.json") let abs_path := path_absolute(config) if path_is_file(abs_path) && path_extension(abs_path) == "json" { # Process config file } - See
examples/stdlib_compression.ruff,examples/stdlib_crypto.ruff,examples/stdlib_process.ruff,examples/stdlib_os.ruff,examples/stdlib_path.ruff - All functions tested with comprehensive test suites in
tests/stdlib_test.ruffandtests/stdlib_os_path_test.ruff
-
Showcase Projects π¨
- Six comprehensive real-world projects demonstrating Ruff capabilities
- Complete examples: log analyzer, task manager, API tester, data pipeline, web scraper, markdown converter
- Each project combines multiple features (arg_parser, file I/O, HTTP, JSON, regex, Result types)
- Production-ready templates for building CLI tools, data processing pipelines, and automation scripts
- See
examples/SHOWCASE_PROJECTS.mdfor complete guide and usage examples
-
Argument Parser π οΈ
- Professional CLI argument parsing with
arg_parser() - Boolean flags, string/int/float options, required/optional arguments, defaults
- Short and long forms (
-v,--verbose), automatic help generation - Fluent API pattern with method chaining
- Example:
parser := arg_parser() parser := parser.add_argument("--verbose", "short", "-v", "type", "bool", "help", "Enable verbose output") parser := parser.add_argument("--config", "type", "string", "required", true) args := parser.parse() if args._verbose { print("Verbose mode enabled") } - See
examples/arg_parser_demo.ruffandtests/arg_parser.rufffor complete examples
- Professional CLI argument parsing with
-
Environment Variable Helpers π§
- Advanced environment variable management:
env_or(),env_int(),env_float(),env_bool(),env_required(),env_set(),env_list() - Get with defaults, parse as types, require or error, set programmatically
- Example:
db_host := env_or("DB_HOST", "localhost")
- Advanced environment variable management:
-
Result & Option Types π
- Robust error handling with
Result<T, E>type - Null safety with
Option<T>type - Pattern matching on
Ok/ErrandSome/Nonevariants - Try operator (
?) for clean error propagation - Example:
func divide(a, b) { if b == 0 { return Err("Division by zero") } return Ok(a / b) } match divide(10, 2) { case Ok(value): { print("Result: " + to_string(value)) } case Err(error): { print("Error: " + error) } } - See
tests/result_option.rufffor comprehensive examples
- Robust error handling with
-
Enhanced Error Messages π―
- Developer-friendly error reporting with contextual information
- "Did you mean?" suggestions for typos using Levenshtein distance
- Helpful guidance for fixing common errors
- Multiple errors reported together (no more one-at-a-time fixing!)
- Example error output:
Type Error: Type mismatch: variable 'x' declared as Int but assigned String --> script.ruff:5:10 | 5 | let x: int := "hello" | ^^^^^^^ | = help: Try removing the type annotation or converting the value to the correct type Undefined Function: Undefined function 'calculat_sum' --> script.ruff:10:5 | = Did you mean 'calculate_sum'? = note: Function must be defined before it is called - See
tests/simple_error_test.ruffandtests/enhanced_errors.ruff
-
Destructuring Patterns π
- Array destructuring:
[a, b, c] := [1, 2, 3] - Dict destructuring:
{name, email} := user - Nested patterns:
[[x, y], z] := [[1, 2], 3] - Rest elements:
[first, ...rest] := [1, 2, 3, 4] - Ignore values:
[x, _, z] := [1, 2, 3] - For-loop destructuring:
for [k, v] in pairs { } - See
examples/destructuring_demo.rufffor examples
- Array destructuring:
-
Spread Operator π
- Array spreading:
[...arr1, ...arr2, ...arr3] - Dict spreading:
{...defaults, ...custom} - Override values:
{...base, timeout: 60} - Clone arrays/dicts:
copy := [...original] - See
examples/spread_operator_demo.rufffor examples
- Array spreading:
-
Bytecode Compiler & VM β‘
- Production-ready stack-based virtual machine
- All language features compile to bytecode
- User-defined and recursive functions fully working
- 60+ optimized bytecode instructions
- CLI integration with
--vmflag - Foundation for future 10-20x performance gains
-
Enhanced Collection Methods π¦
- Comprehensive array utilities (chunk, flatten, zip, enumerate, etc.)
- Advanced dict operations (invert, update, get_default)
- Rich string manipulation (pad, truncate, case conversions)
- 30+ new collection methods
-
Zero Clippy Warnings β¨
- Complete cleanup of all Rust compiler warnings
- Production-grade code quality (271 warnings β 0)
- All 208 tests passing
- Clean, maintainable codebase
-
Standard Library Expansion
- Core modules: os β , path β , io β , net β , crypto β
- Command-line argument parsing β
- Process management and piping β
- Compression and archiving β
- Extended native function library for VM β
-
Async/Await (Future - v0.9.0+)
- Modern async/await syntax
- Concurrent execution with Promise.all/race
- Async iteration
-
Interactive REPL (v0.5.0)
- Full-featured Read-Eval-Print Loop
- Multi-line input with automatic detection
- Command history with up/down arrow navigation
- Line editing with cursor movement
- Special commands:
:help,:quit,:clear,:vars,:reset - Pretty-printed colored output
- Persistent state across inputs
- Error handling without crashes
- Launch with:
ruff repl
-
Variables & Constants
letandmutfor mutable variablesconstfor constants- Shorthand assignment with
:=(e.g.,x := 5) - Optional type annotations:
x: int := 5 - NEW:
:=now properly updates existing variables across scopes
-
Lexical Scoping (v0.3.0)
- Proper scope chain with environment stack
- Variables update correctly across scope boundaries
- Accumulator pattern works:
sum := sum + nin loops - Function local variables properly isolated
- Nested functions can read and modify outer variables
- For-loop variables don't leak to outer scope
- Variable shadowing with
letkeyword
-
Functions
- Function definitions with
funckeyword - Parameter passing with optional type annotations
- Return values with optional return type annotations
- Lexical scoping with access to outer variables
- Functions as first-class values
- Nested function definitions
- NEW: Closures with variable capturing (v0.6.0)
- Functions capture their definition environment
- Closure state persists across calls
- Support for counter patterns and partial application
func make_counter() { let count := 0 return func() { count := count + 1 return count } }
- Function definitions with
-
Control Flow
if/elsestatements- Pattern matching with
match/case loopandforloops- NEW:
whileloops (v0.3.0) - NEW:
breakandcontinuestatements (v0.3.0) - For-in iteration over arrays, dicts, strings, and ranges
try/except/throwerror handling- NEW: Enhanced error handling (v0.4.0) with error properties, custom error types, and stack traces
-
Data Types
- NEW: Integers (i64) and Floats (f64) - Separate types (v0.7.0)
- Integer literals:
42,-10,0 - Float literals:
3.14,-2.5,0.0 - Type preservation:
5 + 3β8(int),5.0 + 3.0β8.0(float) - Integer division truncates:
10 / 3β3 - Mixed operations promote to float:
5 + 2.5β7.5
- Integer literals:
- Strings with escape sequences
- NEW: String interpolation with
${}(v0.3.0):"Hello, ${name}!" - Booleans:
true,false(v0.3.0) - NEW: Null values:
null(v0.6.0) - for optional chaining and default values - Enums with tagged variants
- Arrays:
[1, 2, 3] - Dictionaries:
{"key": value} - Structs with fields and methods
- Functions as first-class values
- NEW: Integers (i64) and Floats (f64) - Separate types (v0.7.0)
-
Collections (v0.2.0)
- Array literals and nested arrays
- Dictionary (hash map) literals
- Index access:
arr[0],dict["key"] - Element assignment:
arr[0] := 10,dict["key"] := value - For-in iteration:
for item in array { },for key in dict { } - Built-in methods:
push(),pop(),slice(),concat(),keys(),values(),has_key(),remove() len()function for strings, arrays, and dicts- NEW: Advanced Collections (v0.6.0)
- Set: Unique value collections with union, intersection, difference operations
users := Set(["alice", "bob", "alice"]) # {"alice", "bob"} users := set_add(users, "charlie") has_bob := set_has(users, "bob") # true - Queue: FIFO (First-In-First-Out) data structure for task processing
tasks := Queue([]) tasks := queue_enqueue(tasks, "task1") result := queue_dequeue(tasks) # [modified_queue, "task1"] - Stack: LIFO (Last-In-First-Out) data structure for undo/history
history := Stack([]) history := stack_push(history, "page1") result := stack_pop(history) # [modified_stack, "page1"]
- Set: Unique value collections with union, intersection, difference operations
-
Array Higher-Order Functions (v0.3.0)
- Functional programming operations for data transformation
map(array, func): Transform each elementsquared := map([1, 2, 3], func(x) { return x * x }) # [1, 4, 9]filter(array, func): Select elements matching conditionevens := filter([1, 2, 3, 4], func(x) { return x % 2 == 0 }) # [2, 4]reduce(array, initial, func): Accumulate into single valuesum := reduce([1, 2, 3, 4], 0, func(acc, x) { return acc + x }) # 10find(array, func): Get first matching elementfound := find([10, 20, 30], func(x) { return x > 15 }) # 20- Chainable for complex data processing
- Anonymous function expressions:
func(x) { return x * 2 }
-
Structs & Methods (v0.2.0)
- Struct definitions with typed fields
- Struct instantiation:
Point { x: 3.0, y: 4.0 } - Field access:
point.x - Method calls:
rect.area(),point.distance() - Self parameter (v0.5.0): Explicit
selffor method compositionstruct Calculator { base: float, func add(self, x) { return self.base + x; } func chain(self, x) { return self.add(x) * 2.0; # Call other methods } } calc := Calculator { base: 10.0 }; result := calc.chain(5.0); # 30.0 - Builder patterns and fluent interfaces
- Backward compatible - methods without
selfstill work
-
Type System (v0.1.0)
- Optional type annotations
- Type inference
- Type checking for assignments and function calls
- Gradual typing - mix typed and untyped code
- Helpful type mismatch error messages
-
Module System (v0.1.0)
- Import entire modules:
import module_name - Selective imports:
from module_name import func1, func2 - Export declarations:
export func function_name() { } - Module caching and circular import detection
- Import entire modules:
-
Built-in Functions
- Math:
abs(),sqrt(),pow(),floor(),ceil(),round(),min(),max(),sin(),cos(),tan(),log()(v0.7.0),exp()(v0.7.0), constantsPIandE - Random (v0.4.0):
random(),random_int(min, max),random_choice(array)- Random number generation - Range (v0.7.0):
range(stop),range(start, stop),range(start, stop, step)- Generate number sequences for loopsfor i in range(5) { print(i) } # 0, 1, 2, 3, 4 for i in range(1, 10, 2) { print(i) } # 1, 3, 5, 7, 9 for i in range(10, 0, 0 - 2) { print(i) } # 10, 8, 6, 4, 2 - Format String (v0.7.0):
format(template, ...args)- sprintf-style string formatting with%s,%d,%fformat("Hello %s", "world") # "Hello world" format("%s has %d apples", "Alice", 5) # "Alice has 5 apples" format("Pi is %.2f", 3.14159) # "Pi is 3.14" - Strings:
len(),to_upper(),to_lower(),trim(),substring(),contains(),replace_str(),starts_with(),ends_with(),index_of(),repeat(),split(),join() - String Methods (v0.7.0):
upper(),lower(),capitalize(),trim_start(),trim_end(),char_at(index),is_empty(),count_chars()- Enhanced string manipulationcapitalize("hello world") # "Hello world" char_at("ruff", 1) # "u" is_empty("") # true - Regex (v0.4.0):
regex_match(),regex_find_all(),regex_replace(),regex_split()- Pattern matching and text processing - Arrays:
push(),pop(),slice(),concat(),len() - Array Higher-Order:
map(),filter(),reduce(),find()(v0.3.0) - Array Utilities (v0.7.0):
sort(),reverse(),unique(),sum(),any(),all()- Essential operations for data processing and analysis - Array Mutation (v0.7.0):
insert(array, index, item),remove(array, item),remove_at(array, index),clear(array),index_of(array, item),contains(array, item)- In-place array operationsarr := [1, 2, 4] arr2 := insert(arr, 2, 3) # [1, 2, 3, 4] arr3 := remove(arr2, 3) # [1, 2, 4] has := contains(arr3, 2) # true - Enhanced Array Methods (v0.8.0):
chunk(),flatten(),zip(),enumerate(),take(),skip(),windows()- Advanced array transformationschunk([1,2,3,4,5], 2) # [[1,2], [3,4], [5]] flatten([[1,2], [3,4]]) # [1,2,3,4] zip([1,2,3], ["a","b","c"]) # [[1,"a"], [2,"b"], [3,"c"]] enumerate(["a","b","c"]) # [[0,"a"], [1,"b"], [2,"c"]] take([1,2,3,4,5], 3) # [1,2,3] skip([1,2,3,4,5], 2) # [3,4,5] windows([1,2,3,4], 2) # [[1,2], [2,3], [3,4]] - Dicts:
keys(),values(),has_key(),remove(),len() - Dict Methods (v0.7.0):
items(dict),get(dict, key, default),merge(dict1, dict2),clear(dict)- Enhanced dictionary operationsuser := {"name": "Alice", "age": 30} pairs := items(user) # [["name", "Alice"], ["age", 30]] email := get(user, "email", "N/A") # "N/A" (not found) combined := merge(user, {"city": "NYC"}) # {"name": "Alice", "age": 30, "city": "NYC"} - Enhanced Dict Methods (v0.8.0):
invert(),update(),get_default()- Advanced dictionary utilitiesinvert({"a":"1", "b":"2"}) # {"1":"a", "2":"b"} update({age:"30"}, {age:"31", city:"NYC"}) # {age:"31", city:"NYC"} get_default(config, "timeout", "30") # Returns value or "30" - Enhanced String Methods (v0.8.0):
pad_left(),pad_right(),lines(),words(),str_reverse(),slugify(),truncate(),to_camel_case(),to_snake_case(),to_kebab_case()- Advanced string transformationspad_left("5", 3, "0") # "005" lines("a\nb\nc") # ["a", "b", "c"] words("hello world") # ["hello", "world"] str_reverse("hello") # "olleh" slugify("Hello World!") # "hello-world" truncate("Hello World", 8, "...") # "Hello..." to_camel_case("hello_world") # "helloWorld" to_snake_case("helloWorld") # "hello_world" to_kebab_case("helloWorld") # "hello-world" - JSON:
parse_json(),to_json()- Parse and serialize JSON data (v0.3.0) - TOML (v0.6.0):
parse_toml(),to_toml()- Parse and serialize TOML configuration files - YAML (v0.6.0):
parse_yaml(),to_yaml()- Parse and serialize YAML documents - CSV (v0.6.0):
parse_csv(),to_csv()- Parse and serialize CSV data files - Date/Time (v0.4.0):
now(),format_date(),parse_date(),current_timestamp()(v0.7.0),performance_now()(v0.7.0),time_us()(v0.7.0),time_ns()(v0.7.0),format_duration()(v0.7.0),elapsed()(v0.7.0) - Complete timing suite with microsecond/nanosecond precision for robust benchmarking - System (v0.4.0):
env(),args(),exit(),sleep(),execute()- Basic system operations- NEW in v0.8.0: Advanced environment variable helpers:
env_or(key, default)- Get environment variable with fallback defaultenv_int(key)- Parse environment variable as integerenv_float(key)- Parse environment variable as floatenv_bool(key)- Parse environment variable as booleanenv_required(key)- Get required environment variable (errors if missing)env_set(key, value)- Set environment variableenv_list()- Get all environment variables as dictionary
- NEW in v0.8.0: Professional CLI argument parsing:
arg_parser()- Create fluent argument parser with.add_argument()and.parse()- Supports boolean flags, string/int/float options, required/optional, defaults
- Short and long forms (
-v,--verbose), automatic help generation - Pass arguments:
ruff run script.ruff --flag --option value
- Enhanced
args()- Returns only script arguments (filters out ruff command)
- NEW in v0.8.0: Advanced environment variable helpers:
- Paths (v0.4.0):
join_path(),dirname(),basename(),path_exists()- Path manipulation - HTTP (v0.5.0):
http_get(),http_post(),http_put(),http_delete(),http_server(),http_response(),json_response(),redirect_response(),set_header()(v0.5.1),set_headers()(v0.5.1) - HTTP client and server with full header control - Concurrency & Parallelism (v0.6.0):
spawn { },parallel_http(),channel(),chan.send(),chan.receive()- Background tasks and parallel HTTP requests for 3x faster API calls - HTTP Authentication (v0.6.0):
jwt_encode(),jwt_decode()- JWT token encoding/decoding for API authentication - OAuth2 (v0.6.0):
oauth2_auth_url(),oauth2_get_token()- OAuth2 flow helpers for third-party authentication - HTTP Streaming (v0.6.0):
http_get_stream()- Memory-efficient downloads for large files - Binary Files (v0.6.0):
http_get_binary(),read_binary_file(),write_binary_file(),encode_base64(),decode_base64()- Download and work with binary data (images, PDFs, archives) - Image Processing (v0.6.0):
load_image(),img.resize(),img.crop(),img.rotate(),img.flip(),img.to_grayscale(),img.blur(),img.adjust_brightness(),img.adjust_contrast(),img.save()- Load, manipulate, and save images (JPEG, PNG, WebP, GIF, BMP) - Database (v0.6.0):
db_connect(db_type, connection_string)- Unified database API supporting SQLite β , PostgreSQL β , and MySQL β ,db_execute(),db_query(),db_close(),db_begin(),db_commit(),db_rollback()- Full CRUD operations with transactions and connection pooling - I/O:
print(),input() - Type Conversion:
parse_int(),parse_float() - Type Introspection (v0.7.0):
type(),is_int(),is_float(),is_string(),is_array(),is_dict(),is_bool(),is_null(),is_function()- Runtime type checking for defensive coding and validation - Assert & Debug (v0.7.0):
assert(condition, message?),debug(...args)- Runtime assertions and detailed debug output for testing and troubleshooting - File I/O:
read_file(),write_file(),append_file(),file_exists(),read_lines(),list_dir(),create_dir(),file_size(),delete_file(),rename_file(),copy_file() - Advanced Binary I/O (v0.8.0):
io_read_bytes(),io_write_bytes(),io_append_bytes(),io_read_at(),io_write_at(),io_seek_read(),io_file_metadata(),io_truncate(),io_copy_range()- Efficient offset-based file operations, metadata access, and byte-range copying - Error handling:
throw()
- Math:
-
Operators
- Arithmetic:
+,-,*,/,%(modulo - v0.3.0) - Comparison:
==,!=(v0.3.0),>,<,>=,<=(returntrue/false- v0.3.0) - String concatenation with
+ - Method Chaining (v0.6.0):
- Null coalescing
??: Return left value if not null, otherwise right valueusername := user?.name ?? "Anonymous" - Optional chaining
?.: Safely access fields, returns null if left side is nullemail := user?.profile?.email # Returns null if any part is null - Pipe operator
|>: Pass value as first argument to functionresult := 5 |> double |> add_ten |> square # Functional data pipelines
- Null coalescing
- Operator Overloading (v0.4.0+): Structs can define custom operator behavior
- Binary operators:
op_add,op_sub,op_mul,op_div,op_mod,op_eq,op_ne,op_gt,op_lt,op_ge,op_le - Unary operators:
op_neg(unary minus-),op_not(logical not!)
- Binary operators:
- Arithmetic:
-
Error Messages
- Colored error output
- Source location tracking
- Line and column information
-
Testing Framework
- Built-in test runner
- Snapshot testing with
.outfiles - Test result reporting
See Install Guide for platform setup instructions.
Install Rust and run:
# Clean output (recommended)
cargo run --quiet -- run examples/your_script.ruff
# Or with build messages
cargo run -- run examples/your_script.ruff
# Use bytecode VM for faster execution (experimental)
cargo run -- run examples/your_script.ruff --vmRuff includes an experimental bytecode compiler and virtual machine for improved performance:
# Run with bytecode VM
ruff run examples/factorial.ruff --vmCurrent Status:
- β Core VM architecture complete
- β User-defined functions work correctly
- β Basic arithmetic, control flow, arrays, dicts
β οΈ Limited built-in function support (parser issue being fixed)β οΈ No benchmarks yet - performance improvements to be measured
How it works:
- Ruff AST is compiled to stack-based bytecode
- Virtual machine executes bytecode instructions
- Designed for 10-20x performance improvement over tree-walking interpreter
Use cases:
- Performance-critical scripts
- Testing VM functionality
- Comparing execution speeds
Note: The VM is under active development. Some features may not work correctly. Fall back to the default tree-walking interpreter (without --vm flag) if you encounter issues.
Launch the interactive shell for experimentation and learning:
cargo run --quiet -- replThe REPL provides a powerful interactive environment:
Features:
- β Multi-line input - Automatically detects incomplete statements
- β Command history - Navigate with up/down arrows
- β Line editing - Full cursor movement and editing support
- β Persistent state - Variables and functions stay defined
- β Pretty output - Colored, formatted value display
- β
Special commands -
:help,:quit,:clear,:vars,:reset
Example Session:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Ruff REPL v0.5.0 - Interactive Shell β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Welcome! Use :help for commands or :quit
Tip: Multi-line input: End with unclosed braces
ruff> let x := 42
ruff> x * 2
=> 84
ruff> func factorial(n) {
....> if n <= 1 {
....> return 1
....> }
....> return n * factorial(n - 1)
....> }
ruff> factorial(5)
=> 120
ruff> let names := ["Alice", "Bob", "Charlie"]
ruff> names
=> ["Alice", "Bob", "Charlie"]
ruff> :help
# Shows available commands
ruff> :quit
Goodbye!
Tips:
- Type
:helpto see all available commands - Press Ctrl+C to interrupt current input
- Press Ctrl+D or type
:quitto exit - Leave braces unclosed for multi-line input
- Any expression automatically prints its result
Example:
enum Result {
Ok,
Err
}
func check(x) {
if x > 0 {
return Result::Ok("great")
}
return Result::Err("bad")
}
res := check(42)
match res {
case Result::Ok(msg): {
print("β", msg)
}
case Result::Err(err): {
print("β", err)
}
}
Comprehensive error handling with error properties, custom error types, and stack traces:
# Access error properties
try {
throw("Something went wrong")
} except err {
print("Message:", err.message)
print("Line:", err.line)
print("Stack depth:", len(err.stack))
}
# Custom error types with structs
struct ValidationError {
field: string,
message: string
}
func validate_email(email: string) {
if !contains(email, "@") {
error := ValidationError {
field: "email",
message: "Email must contain @ symbol"
}
throw(error)
}
}
try {
validate_email("invalid")
} except err {
print("Validation failed:", err.message)
}
# Error chaining with cause
struct DatabaseError {
message: string,
cause: string
}
try {
connect_to_db()
} except conn_err {
error := DatabaseError {
message: "Failed to initialize app",
cause: conn_err.message
}
throw(error)
}
# Stack traces from nested function calls
func inner() {
throw("Error from inner")
}
func outer() {
inner()
}
try {
outer()
} except err {
print("Error:", err.message)
print("Call stack:", err.stack)
}
Build HTTP servers and make HTTP requests with ease:
HTTP Client:
# Make HTTP GET request
result := http_get("https://api.example.com/users")
if result.is_ok {
data := result.value
print("Status:", data["status"])
print("Body:", data["body"])
}
# POST request with JSON body
user_data := {"name": "Alice", "email": "alice@example.com"}
result := http_post("https://api.example.com/users", user_data)
# PUT and DELETE requests
http_put("https://api.example.com/users/1", {"name": "Bob"})
http_delete("https://api.example.com/users/1")
HTTP Server:
# Create HTTP server on port 8080
server := http_server(8080)
# Register GET route
server.route("GET", "/hello", func(request) {
return http_response(200, "Hello, World!")
})
# Register POST route with JSON response
server.route("POST", "/api/data", func(request) {
data := {"received": request.body, "method": request.method}
return json_response(200, data)
})
# Start server (blocks and handles requests)
print("Server listening on http://localhost:8080")
server.listen()
REST API Example:
# In-memory data store
todos := []
server := http_server(8080)
# GET all todos
server.route("GET", "/todos", func(request) {
return json_response(200, todos)
})
# POST new todo
server.route("POST", "/todos", func(request) {
todo := parse_json(request.body)
push(todos, todo)
return json_response(201, todo)
})
print("REST API running on http://localhost:8080")
server.listen()
Download and work with binary files like images, PDFs, and archives:
# Download binary file from URL
image_data := http_get_binary("https://example.com/photo.jpg")
write_binary_file("photo.jpg", image_data)
print("Downloaded:", len(image_data), "bytes")
# Read binary file
file_bytes := read_binary_file("document.pdf")
# Base64 encoding for API transfers
base64_str := encode_base64(file_bytes) # Also accepts strings
decoded := decode_base64(base64_str)
# Example: Download AI-generated image
# After calling image generation API...
generated_url := api_response["image_url"]
image := http_get_binary(generated_url)
write_binary_file("ai_generated.png", image)
# Embed in JSON
json_payload := {
"image": encode_base64(image),
"format": "png"
}
Efficient binary file operations with offset-based access and metadata:
# Read specific number of bytes
header := io_read_bytes("image.png", 8) # First 8 bytes for format detection
# Offset-based reading and writing
data := io_read_at("data.bin", 1000, 512) # Read 512 bytes at offset 1000
io_write_at("config.bin", patch_data, 22) # Update at specific offset
# Read from offset to end
tail := io_seek_read("app.log", file_size - 1024) # Last 1KB of logs
# Append binary data efficiently
io_append_bytes("stream.dat", new_chunk)
# Copy byte ranges between files (zero-copy)
io_copy_range("source.bin", "extract.bin", 5000, 2000) # Copy 2KB from offset 5KB
# Get comprehensive file metadata
meta := io_file_metadata("document.pdf")
print("Size: ${meta["size"]} bytes")
print("Modified: ${meta["modified"]} (timestamp)")
print("Type: ${meta["is_file"] ? "File" : "Directory"}")
print("Read-only: ${meta["readonly"]}")
# Manage file sizes
io_truncate("log.txt", 10000) # Shrink to 10KB
# Use cases:
# - Binary format detection (read headers without loading full file)
# - Log analysis (read last N bytes)
# - In-place patching (update config without rewriting)
# - Efficient data extraction (copy ranges from large files)
# - Stream processing (append chunks incrementally)
HTTP Headers (v0.5.1):
# Add individual headers
response := http_response(200, "Success")
response := set_header(response, "X-API-Version", "1.0")
response := set_header(response, "Cache-Control", "max-age=3600")
# Set multiple headers at once
headers := {
"X-Request-ID": "abc-123",
"X-Rate-Limit": "1000",
"Access-Control-Allow-Origin": "*"
}
response := set_headers(response, headers)
# JSON responses automatically include Content-Type
json := json_response(200, {"status": "success"}) # Includes Content-Type: application/json
# Redirects with custom headers
redirect_headers := {"X-Redirect-Reason": "Moved permanently"}
redirect := redirect_response("https://new-url.com", redirect_headers)
# Access request headers in route handlers
server.route("POST", "/api/upload", func(request) {
content_type := request.headers["Content-Type"]
auth_token := request.headers["Authorization"]
if content_type != "application/json" {
return http_response(400, "Invalid Content-Type")
}
response := json_response(200, {"uploaded": true})
return set_header(response, "X-Upload-ID", "upload-123")
})
Key Features:
- HTTP methods: GET, POST, PUT, DELETE
- Path-based routing with exact matching
- JSON request/response handling
- Automatic request body parsing
- Request body parsing (JSON)
Run code concurrently for faster AI tools, batch processing, and non-blocking operations:
Parallel HTTP Requests (3x faster for AI model comparison):
# Query multiple AI providers simultaneously
urls := [
"https://api.openai.com/v1/chat/completions",
"https://api.anthropic.com/v1/messages",
"https://api.deepseek.com/v1/chat/completions"
]
# All 3 requests happen in parallel - returns in ~2s instead of 6s!
results := parallel_http(urls)
for result in results {
print("Status: " + result["status"])
print("Response: " + result["body"])
}
Background Tasks with spawn:
# Fire and forget - main thread continues immediately
spawn {
print("Processing in background...")
process_large_file()
}
print("Main thread continues without waiting")
Thread Communication with Channels:
chan := channel()
spawn {
result := expensive_computation()
chan.send(result)
}
# Receive result from background thread
value := chan.receive()
print("Got result: " + value)
Key Features:
- 3x faster parallel HTTP requests for AI model comparison
- Non-blocking background tasks with
spawn - Thread-safe communication with channels
- Perfect for batch processing and data pipelines
Load, manipulate, and save images with built-in support for JPEG, PNG, WebP, GIF, and BMP:
# Load and inspect image
img := load_image("photo.jpg")
print("Size: " + img.width + "x" + img.height)
print("Format: " + img.format)
# Create thumbnail (maintain aspect ratio)
thumb := img.resize(200, 200, "fit")
thumb.save("thumbnail.jpg")
# Exact dimensions
resized := img.resize(800, 600)
resized.save("resized.jpg")
# Crop region (x, y, width, height)
cropped := img.crop(100, 100, 400, 300)
cropped.save("cropped.jpg")
# Transformations
rotated := img.rotate(90) # 90, 180, or 270 degrees
flipped := img.flip("horizontal") # or "vertical"
# Filters and adjustments
gray := img.to_grayscale()
blurred := img.blur(5.0) # sigma value
brighter := img.adjust_brightness(1.2) # 20% brighter
contrast := img.adjust_contrast(1.3) # More contrast
# Method chaining for complex workflows
enhanced := img
.resize(800, 600)
.adjust_brightness(1.1)
.adjust_contrast(1.15)
.to_grayscale()
enhanced.save("enhanced.jpg")
# Format conversion (auto-detects from extension)
img.save("output.png") # JPEG -> PNG
img.save("output.webp") # JPEG -> WebP
# Batch processing
images := ["img1.jpg", "img2.jpg", "img3.jpg"]
for path in images {
img := load_image(path)
thumb := img.resize(200, 200, "fit")
# Extract filename
parts := split(path, ".")
name := parts[0]
thumb.save("thumbs/" + name + "_thumb.jpg")
}
# Social media image prep
func prepare_instagram_post(image_path) {
img := load_image(image_path)
# Instagram: 1080x1080
resized := img.resize(1080, 1080, "fit")
# Enhance for social media
enhanced := resized
.adjust_brightness(1.1)
.adjust_contrast(1.15)
enhanced.save("instagram_post.jpg")
}
Supported Operations:
-
Load/save: JPEG, PNG, WebP, GIF, BMP
-
Resize: exact dimensions or maintain aspect ratio
-
Transform: crop, rotate (90/180/270), flip (h/v)
-
Filters: grayscale, blur (Gaussian)
-
Adjust: brightness, contrast
-
Properties: width, height, format
-
Method chaining for complex workflows
-
Error handling for missing/invalid files
-
Built-in response helpers
-
Error handling with proper status codes
-
Full header control:
- Custom response headers
- Automatic headers (Content-Type for JSON)
- Request header access
- CORS support
- Security headers
See examples/http_server_simple.ruff, examples/http_rest_api.ruff, examples/http_client.ruff, examples/http_webhook.ruff, and examples/http_headers_demo.ruff for complete examples.
Ruff includes a unified database API that works across different database backends. Currently supports SQLite, PostgreSQL, and MySQL:
# SQLite - Perfect for local apps and embedded databases
db := db_connect("sqlite", "myapp.db")
db_execute(db, "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)", [])
db_execute(db, "INSERT INTO users (name, email) VALUES (?, ?)", ["Alice", "alice@example.com"])
users := db_query(db, "SELECT * FROM users", [])
# PostgreSQL - Perfect for production web applications
db := db_connect("postgres", "host=localhost dbname=myapp user=admin password=secret")
db_execute(db, "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT, email TEXT)", [])
db_execute(db, "INSERT INTO users (name, email) VALUES ($1, $2)", ["Alice", "alice@example.com"])
users := db_query(db, "SELECT * FROM users", [])
# MySQL - Perfect for traditional web applications
db := db_connect("mysql", "mysql://root@localhost:3306/myapp")
db_execute(db, "CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), email VARCHAR(100))", [])
db_execute(db, "INSERT INTO users (name, email) VALUES (?, ?)", ["Alice", "alice@example.com"])
users := db_query(db, "SELECT * FROM users", [])
# Same Ruff code works with all databases!
for user in users {
print("User: " + user["name"] + " - " + user["email"])
}
# Query with parameters (prevents SQL injection)
bob := db_query(db, "SELECT * FROM users WHERE name = $1", ["Bob"]) # PostgreSQL uses $1, $2
# bob := db_query(db, "SELECT * FROM users WHERE name = ?", ["Bob"]) # SQLite & MySQL use ?
# Update and delete
db_execute(db, "UPDATE users SET email = $1 WHERE name = $2", ["alice@newmail.com", "Alice"])
db_execute(db, "DELETE FROM users WHERE name = $1", ["Bob"])
# Close connection
db_close(db)
Key Features:
- Unified API: Same
db_connect(),db_execute(), anddb_query()functions work across all databases - SQLite Support:
?placeholders for parameters - PostgreSQL Support:
$1, $2, $3placeholders for parameters - MySQL Support:
?placeholders for parameters (async driver with transparent blocking) - Parameter Binding: Prevents SQL injection attacks
- Type Safety: Returns proper Null values for NULL database fields
- Type Support: Integers, floats, strings, booleans, and NULL
- Multi-Backend Ready: Switch databases by changing connection string only
Database-Specific Syntax Notes:
- SQLite: Uses
?for parameters:INSERT INTO users VALUES (?, ?) - PostgreSQL: Uses
$1, $2for parameters:INSERT INTO users VALUES ($1, $2) - MySQL: Uses
?for parameters:INSERT INTO users VALUES (?, ?) - Everything else is the same Ruff code!
See examples/database_unified.ruff for comprehensive SQLite examples, examples/database_postgres.ruff for PostgreSQL examples, examples/database_mysql.ruff for MySQL examples, and examples/projects/url_shortener.ruff for a complete URL shortener using SQLite with an HTTP server.
name := "Alice"
age := 30
score := 95
# Embed expressions directly in strings
greeting := "Hello, ${name}!"
bio := "${name} is ${age} years old"
result := "Score: ${score}/100 (${score >= 90}% = A)"
print(greeting) # Hello, Alice!
print(bio) # Alice is 30 years old
print(result) # Score: 95/100 (true% = A)
# Complex expressions with parentheses
a := 2
b := 3
c := 4
calculation := "Result: (${a} + ${b}) * ${c} = ${(a + b) * c}"
print(calculation) # Result: (2 + 3) * 4 = 20
Ruff supports three types of comments:
# Single-line comment
# These continue to end of line
/*
* Multi-line comments
* Span multiple lines
* Useful for longer explanations
*/
/// Doc comments for documentation
/// @param x The input value
/// @return The result
func square(x) {
return x * x /* inline comment */
}
# All comment types work together
/*
* Block comment explaining the algorithm
*/
/// Documentation for the function
func calculate(n) {
# Implementation details
return n * 2
}
See examples/comments.ruff for comprehensive examples.
Place test files in the tests/ directory. Each .ruff file can have a matching .out file for expected output:
cargo run -- testTo regenerate expected .out snapshots:
cargo run -- test --update- β Mutable/const variables with optional type annotations
- β Functions with return values and type annotations
- β
Pattern matching with
match/case - β Enums with tagged variants
- β Nested pattern matches
- β
try/except/throwerror handling - β Structs with fields and methods (v0.2.0)
- β Arrays with element assignment and iteration (v0.2.0)
- β Dictionaries (hash maps) with built-in methods (v0.2.0)
- β For-in loops over arrays, dicts, strings, and ranges (v0.2.0)
- β
Built-in collection methods:
push(),pop(),slice(),concat(),keys(),values(),has_key(),remove(),len()(v0.2.0) - β Type system with type checking and inference (v0.1.0)
- β Module system with import/export (v0.1.0)
- β
String interpolation with
${}syntax (v0.3.0) - β Boolean type as first-class value (v0.3.0)
- β
Loop control with
while,break, andcontinue(v0.3.0) - β Lexical scoping with proper environment stack (v0.3.0)
- β Multi-line and doc comments (v0.3.0)
- β Standard library with math, string, and I/O functions
- β CLI testing framework with snapshot testing
- β Colored error messages with source location tracking
See ROADMAP.md for detailed feature plans.
View the CONTRIBUTING document.