pyalt is a small compiled language with Python-like syntax.
It builds standalone native executables — no interpreter, no GIL.
parallel for spreads a loop across every core, and data races
are compile errors.
>
trades=84770 wins=21929 mean_eq=8165
✓ output byte-identical across all three
parallelism
200 simulated price paths, 50,000 steps each, an EMA-crossover strategy with stop-losses — per-step state that cannot be vectorized. The serial and parallel programs differ by a single keyword.
eqs = [0.0] * paths
for p in range(paths): r = run_path(p + 1, steps)
eqs[p] = r.equity
eqs = [0.0] * paths
parallel for p in range(paths): r = run_path(p + 1, steps)
eqs[p] = r.equity
the same three times drawn to linear scale — pyalt’s are the slivers
safety
Every threaded language has the same horror story: works in
testing, corrupts data in production. pyalt’s answer: assigning to shared
state inside parallel for is rejected before the program
ever runs. This is the compiler’s actual output:
race.pya:6:5: error: cannot assign to outer variable 'total'
inside parallel for — iterations race; write results into an
output list instead
total = total + score(i)
^
The one blessed pattern — writing results into distinct slots of an output list — is race-free by construction. And since pyalt functions cannot touch globals, every function called from a parallel loop is thread-safe automatically. Appending to a shared list, writing a shared dict, returning from inside the loop: all compile errors, each with an explanation.
benchmarks
Monte Carlo backtest, 10 million loop iterations, identical logic in each implementation, byte-identical outputs, median of 5 runs on Windows 11 x64. The harness re-verifies pyalt’s output against CPython’s on every run.
| implementation | serial | parallel | notes |
|---|---|---|---|
| CPython 3.11 | 3.088 s | — | GIL prevents thread parallelism |
Numba 0.59 @njit | 0.041 s | 0.0068 s | ~2.2 s JIT compile on first call; prange races are silent |
| pyalt | 0.049 s | 0.0089 s | ahead-of-time; no warmup; races are compile errors |
Serial string- and dict-heavy code is the weaker case — roughly
2.5–5x over CPython, whose string and dict internals are already
optimized C; parallel for reached 15x on the same text workload.
Full methodology in
BENCHMARKS.md;
reproduce everything with python bench/harness.py.
language
Every feature below is covered by the 216-test suite that CI runs on Windows and Linux. Annotate function parameters; everything else is inferred at compile time.
class Result:
equity: float
trades: int
wins: int
def run_path(seed: int, steps: int) -> Result:
price = 100.0 # float, inferred
...
return Result(equity, trades, wins)
try:
values = parse_row(line)
total = total + values[2] # bounds-checked
except as msg:
print(f"skipping row: {msg}")
raise "empty input file"
from utils import clean
import stats
rows = clean(read_lines("data.csv"))
m = stats.mean(rows)
# the import graph compiles into ONE binary;
# import cycles are compile errors
> pyalt buildpy metrics.pya
build\metrics.pyd
# then, in ordinary Python:
import metrics
metrics.sharpe(returns) # native speed
int · float · bool · str · list[T] · dict[K,V] · set[T]gc_collect()args() · input() · exists() · exit()PYA_THREADS · PYA_GC env knobsread before porting
Machine performance costs some Python behaviors. These are the differences that matter, stated up front:
int is 64-bit, not arbitrary precision.
10**19 overflows in pyalt and works in Python; the usable range
ends at ±9.2×10¹⁸.len(), indexing, and
slicing count bytes. Identical to Python for ASCII, different for
non-ASCII text.float matches CPython bit-for-bit in arithmetic
(verified by the harness); // and % follow Python’s
floor/sign rules. Float formatting can differ in edge cases.except
catches everything; there is no exception class hierarchy yet.None; conditions must be bool;
a variable keeps one type. All three are compile errors rather than
silent differences.install
Get pyalt-0.1.0-windows-x64.zip
(7 MB, self-contained — no Python required) and unzip anywhere,
e.g. C:\pyalt.
The included script appends bin\ to your user PATH.
Windows requires downloaded scripts to be run explicitly — then open a
new terminal:
powershell -ExecutionPolicy Bypass -File .\install.ps1
Building needs a C compiler on the machine — MSVC
(free Build Tools),
gcc, or clang, detected automatically. Save as hello.pya:
def fib(n: int) -> int:
if n < 2: return n
return fib(n - 1) + fib(n - 2)
print(f"fib(30) = {fib(30)}")
pyalt run hello.pya # compile and run
pyalt build hello.pya # build\hello.exe — ~200 KB, zero deps
pyalt buildpy hello.pya # build\hello.pyd — import from Python
Linux and macOS run from source — python3 pyalt.py run prog.pya
(Python 3.10+); the full test suite passes on Ubuntu in CI, less
field-tested than Windows.
SHA256 pyalt-0.1.0-windows-x64.zip
A889628D820D0D84E8584FE792F56524C6F3A8EE13A8DA62D943B95560BDC60B
how it works
The runtime is a single C header (~1,300 lines): a conservative mark-sweep
garbage collector, insertion-ordered hash tables with cached string hashes,
zero-copy string views, a thread pool for parallel for, and bounds
checks throughout. The compiler (~3,700 lines) is currently bootstrap-hosted
in Python — the usual arrangement for a young language; the release package
is self-contained, and compiled output never involves Python.
Compile errors carry position, context, and a suggestion:
prog.pya:3:19: error: '+' has mismatched operand types: int and str
— to build a string, convert with str(...) or use an f-string
total = total + line
^
roadmap
None / OptionalDevelopment practice: no change merges without tests, and the benchmark harness verifies pyalt’s outputs against CPython’s on every run.