Why Sifr exists
Most high-level languages trade safety for convenience. You get concise syntax, but you also get runtime exceptions, null pointer crashes, and garbage-collected pauses. Rust solves those problems but demands a steep learning curve: lifetime annotations, explicit borrows, and a type system that can feel hostile to newcomers. Sifr takes a different approach. It borrows Rust’s safety model and maps it onto Python’s syntax, so the concepts that protect your program — ownership,Option, Result — are expressed in terms you already recognize. The compiler does the translation; you write the logic.
Key value propositions
Write Python, run Rust. Sifr files use.sifr extensions and Python syntax. def, for, if, class, f-strings — all the constructs you already know. The compiler emits Rust source and builds a native binary. No virtual machine, no interpreter, no garbage collector at runtime.
No runtime crashes. Dictionary lookups and list indexing return Option rather than throwing exceptions. The compiler forces you to handle the None case before the program can run. A missing key can never crash a production binary.
No exceptions — real error handling. try/except in Sifr is pattern matching on Result, not stack unwinding. Functions that can fail declare Result[T, E] in their return type, and the compiler issues an error if you forget to handle the failure branch.
Ownership without the pain. Function arguments borrow by default — no & sigils required. You can use a value after passing it to a function without the compiler complaining, because Sifr infers the correct lifetime. You get Rust’s memory safety guarantees without writing Rust’s borrow syntax.
TypeScript-style types. Union types, literal types, and automatic type narrowing are first-class citizens. int | str, int | None, isinstance narrowing — the type system works the way a Python developer would expect it to, while still being fully static.
A complete example
The program below demonstrates union types, safe dictionary indexing, and type narrowing — three features that work together to eliminate an entire class of runtime bugs.users["charlie"] raises a KeyError at runtime. In Sifr, the return type is int | None, and the compiler refuses to let you treat age as a plain int until you have checked the None branch. The bug is caught before the binary is built.
Error handling with Result
Sifr replaces exceptions withResult types. Functions that can fail declare their error type explicitly, and the compiler tracks whether every call site handles the failure.
raise statement inside a Result-returning function produces an Err variant, not a stack unwind. The try/except block at the call site is pattern matching, not exception catching. If you remove the except branch, the compiler tells you — at compile time, not in production.
Ownership by default
Sifr functions borrow their arguments automatically. You never need to think about moves unless you explicitly want them.longest(names) returns, names is still valid and usable. The compiler infers the borrow automatically. You get the memory safety of Rust without annotating a single lifetime.
Sifr is currently in preview. The alpha and beta channels are available for early adopters. See the Installation page to get started.