Rc for shared ownership.@native.WIDTH, HEIGHT, MAX_ITER = 64, 28, 90 CHARS = " .:-=+*#%@" def escape(cx: float, cy: float) -> int: x, y = 0.0, 0.0 for i in range(MAX_ITER): if x*x + y*y > 4.0: return i x, y = x*x - y*y + cx, 2.0*x*y + cy return MAX_ITER def main() -> None: for row in range(HEIGHT): cy = -1.2 + 2.4 * row / HEIGHT for col in range(WIDTH): cx = -2.4 + 3.2 * col / WIDTH idx = escape(cx, cy) % len(CHARS) print(CHARS[idx], end="") print("") main()
The entire TurboPython toolchain is an ordinary Python package, published on PyPI as
tpy-lang; installing the package is the whole setup. Compilation uses a C++23 compiler
on the PATH—GCC 13+ or Clang 19+. The tpy-lang[bundled] option comes with
a compiler included.
Without a C++ compiler on the PATH, 'tpy-lang[bundled]' installs a self-contained compiler.
GCC 13+ ships with most current Linux distributions; on macOS, a recent Homebrew LLVM/Clang works. On Windows, the recommended setup is WSL.
Type annotations are required on function parameters, return types, and class
fields; an unannotated integer literal defaults to a 32-bit Int32. Beyond these
rules, most code reads like standard Python—minus Python's dynamic runtime features. Where a construct diverges from the static type and
ownership model, the compiler reports it, and its diagnostics name the required change.
Python reclaims objects automatically through reference counting, so a name is just a shared reference. TurboPython has no garbage collector: every value has exactly one owner — a function frame, a field, or a container — and the owner controls when it is freed. Locals and parameters still alias as they do in Python; persistent storage owns its values. Three cases follow, each shown with the compiler's actual output.
def make() -> Obj: o = Obj(1) return o # freed when make returns
def make() -> Own[Obj]: o = Obj(1) return o # ownership moves to the caller
o lives in make's frame and is freed when the function returns;
returning it by reference would leave a dangling pointer. Own[Obj] hands the value itself to
the caller, who becomes its owner.
class Cache: item: Tag def __init__(self, t: Tag) -> None: self.item = t # Python would share a reference
class Cache: item: Tag def __init__(self, t: Own[Tag]) -> None: self.item = t # the field takes ownership
A field outlives the call that sets it, so it must own its value. Declaring the parameter
Own[Tag] transfers the caller's object in; copy(t) is the alternative when the caller
keeps its own. Fields are declared as typed class attributes and set in __init__ —
there is no __dict__, so each one is a fixed, typed slot.
l = [] o = Obj(1) l.append(o) # implicit copy: o is used below o.x = 99
l = [] o = Obj(1) l.append(copy(o)) o.x = 99 # the list holds its own copy
A list stores objects, not references, so the append copies either way — where Python
would share the same object. copy() doesn't introduce the copy; it makes the unavoidable one
explicit and clears the warning. If o weren't used afterward, it would be moved
into the list instead — no copy at all.
Ownership is the conceptual shift. The rest are smaller, mechanical rules — the type system's requirements, and the constraints a compiled language places on Python's more dynamic features. They become familiar within the first few files.
Function parameters, returns, and class fields are annotated; local variables are inferred. Python's optional hints become the contract.
A bare integer is a 32-bit Int32. Int64/UInt32/... pick a width; int is arbitrary-precision (heap-allocated for large values).
Primitives, tuples and views copy; classes, list, dict, set are reference types, passed and returned by reference.
A str is an owned string or a borrowed view depending on context; String and StrView spell it out. Plain str is the right default when allocations are acceptable.
No eval, monkey-patching, or runtime __dict__ mutation. Types and structure are fixed at compile time.
tpyTurboPython's own types (Own, Int32, Span, ...) live in the tpy module — a file can pull them all in with from tpy import *.
tpy --install-agent-docs docs writes a
TurboPython primer alongside the code — the Python-to-TPy delta, the ownership rules, and the
idioms an assistant needs to generate correct TurboPython.