Skip to main content
Sifr uses Python-shaped syntax, but it is not Python with a faster runtime. It is a compiled language with static types, ownership, and typed errors. The syntax should feel familiar; the contract is stricter.

Same Shape, Different Contract

If you know Python, start by keeping the surface model and changing the failure model. Sifr tries to make illegal states visible before a binary is built: missing values are typed, fallible calls return Result, and values crossing ownership or task boundaries must be explicit.

What Carries Over

You still write def, class, if, for, list and dict literals, comprehensions, f-strings, match, async def, and await. The goal is not to make you learn a new surface grammar before you can write useful programs.
The difference is that annotations are part of the program. If describe promises str, every path must return str.

What Changes At Compile Time

Sifr turns several Python runtime surprises into compile-time obligations:
  • a dictionary lookup that might miss returns V | None;
  • a fallible function returns Result[T, E];
  • a parameter is immutable unless marked mut;
  • a value is borrowed by default unless a function asks for own;
  • a spawned task can only capture values that are owned and sendable.
Sifr docs are the source of truth for Sifr semantics. Python references are useful for syntax vocabulary, but they do not define Sifr’s type, ownership, error, or package model.

Common Surprises

Sifr annotations are checked before the program runs. Treat them as part of the language, not as documentation for a separate runtime.
raise inside a Result-returning function produces an error value. try/except handles that value explicitly.
Use from sifr.collections import Counter, not import collections. Supported stdlib-style modules live under sifr.*; see the collections import example.
Use sifr.python when you intentionally embed CPython and call packages from a uv-created environment. Configure the root package’s [python] and [trust] tables first; see Embedded Python Interop.
Use mut when a function should mutate a borrowed parameter, and own mut when it should take ownership and mutate the value.

Where To Go Next

Mental Model Shift

Follow the practical path from Python habits to Sifr’s compile-time model.

Ownership and Mutability

Learn mut, own, and borrow-by-default rules.

Error Handling

See how Result and try/except replace recoverable exceptions.

Embedded Python Interop

Call installed Python packages through explicit environment and trust boundaries.