Decorators
Decorators work the same as in Python. Typhon adds a small set of build-time-only decorators.
Standard Python decorators
import functools
@functools.cachedef f(n: int) -> int: ...
@functools.wraps(f)def wrapper(...): ...
@staticmethoddef helper() -> int: ...
@classmethoddef from_dict(cls, data: dict) -> Self: ...
@propertydef value(self) -> int: ...All work as Python expects them to.
Typhon-specific decorators
These are recognised by the analyser, used at build time, and either erased or transformed at emit.
@pure
Asserts a function is pure per the six conditions. Erased at emit.
@puredef normalise(s: str) -> str: return s.strip().lower()@memo
Inserts @functools.cache (or @functools.lru_cache(maxsize=N) for @memo(max=N)). Function must qualify as pure.
@memodef fib(n: int) -> int: ...@pure(memo=True)
Combined form of @pure + @memo.
@pure(memo=True)def hash_pw(salt: str, pw: str) -> str: ...@gatherable
Opts a function into automatic-gather rewriting (only fires when [strictness] auto-gather = true):
@gatherableasync def fetch_user(uid: int) -> User: ...Without the decorator, auto-gather skips this callee.
Decorator order
For Python-standard decorators, order matters as it does in Python (innermost first). For Typhon-specific decorators, order doesn’t matter — they are processed as a set at desugar time.
@pure # processed as a set with @memo@memodef f(...) -> ...: ...
# equivalent to:@memo @pure def f(...) -> ...: ...# equivalent to:@pure(memo=True) def f(...) -> ...: ...Custom decorators
Standard Python decorators work without ceremony:
def timing(f): import time, functools @functools.wraps(f) def wrapper(*args, **kwargs): t0 = time.time() result = f(*args, **kwargs) print(f"{f.__name__}: {time.time() - t0:.3f}s") return result return wrapper
@timingdef expensive(): ...The decorator must be in scope at the decoration site, like in Python.
Type-checking decorators
The checker preserves the wrapped function’s signature when the decorator is a typed function (Callable[[F], F] for parameter-preserving decorators). For decorators that change signatures, it may lose precision — annotate the decorated function explicitly when this matters.
Where next
@pureand@memo— the purity decorators in depth.async,await,gather,go—@gatherablefor auto-gather.