A small, fast scripting language with its own simple syntax β blocks close
with end, not indentation. Shipped as one static binary, with no-GIL parallel
async/await, structs, modules, slicing and a batteries-included standard library β
and it compiles to native machine code.
Simple syntax, without significant whitespace: blocks open with a keyword
and close with end. Indentation is purely cosmetic.
# fib.cobra
def fib(n)
if n < 2
return n
end
return fib(n - 1) + fib(n - 2)
end
for i in range(8)
print(fib(i))
end
$ cobra fib.cobra # tree-walking engine $ cobra --vm fib.cobra # bytecode VM (the fast one) $ cobra --native fib.cobra # compile to machine code, run it $ cobra # REPL, multi-line aware $ cobra build fib.cobra # compile to fib.cobrac $ cobra fib.cobrac # run the compiled bytecode
0 1 1 2 3 5 8 13
Built layer by layer β lexer, Pratt parser, tree-walking evaluator, then a bytecode compiler and stack VM β with one rule throughout: every feature lands in both engines, verified to behave identically, tested at every layer.
cobra build --native turns a program into a standalone
machine-code executable β no interpreter, no bytecode. Whole-program type
inference unboxes your integers and floats and lays structs out flat, so the
binary runs the numeric benchmarks faster than PyPy's JIT and needs
nothing installed to run.
For everything else, the VM runs the benchmark suite ~4x faster than the tree-walker β registerized dispatch, fused superinstructions, allocation arenas, small-int interning, and a custom dict with cached string hashes.
No interpreter install, no venv, no dependency hell. Copy a ~7 MB binary
anywhere and run .cobra source or compiled .cobrac bytecode.
Real multi-core parallelism: async tasks run on every
core at once β real speedup on CPU-bound work, not just I/O overlap. Guard
shared state with Mutex, pass values over Channel.
await works at the top level.
Undefined variables, assignment to builtins and misplaced break
are compile-time errors. Runtime errors carry line numbers β identical
messages from both engines.
Eleven native modules: fs, math, os,
json, time, re, http
(client and server), proc, net,
test (a built-in unit-test framework) and runtime
(GC + memory stats). All failures catchable.
Multi-line REPLs on both engines, an LSP server (cobra lsp)
with live diagnostics from the real parser and compiler, and a VS Code
extension with highlighting and IntelliSense.
Six workloads, run on both of Cobra's engines on an Apple M-series laptop (wall clock, best of 3). The harness refuses to report numbers unless both engines print byte-identical output β the benchmarks double as a cross-engine correctness check. The VM runs the suite ~4x faster than the tree-walker.
| benchmark | workload | tree-walk | VM | speedup |
|---|---|---|---|---|
| fib | fib(32), recursive calls | 1.40s | 0.13s | 10.6x |
| loop | 10M-iteration while + arithmetic | 1.21s | 0.34s | 3.6x |
| lists | build + iterate 2M elements | 0.32s | 0.12s | 2.7x |
| dicts | 1M inserts + lookups | 0.30s | 0.18s | 1.7x |
| strings | 200k concat/join/split/endswith | 0.07s | 0.03s | 2.1x |
| structs | 1M instantiations + method calls | 0.65s | 0.16s | 4.2x |
| total | 3.95s | 0.95s | 4.1x |
These are microbenchmarks. Cobra's lane is fast hermetic scripts, embedded scripting, and being small enough to fully understand.
The same programs, compiled to machine code with
cobra build --native, against the fastest ways to run the equivalent
Python: CPython 3.14 and PyPy's tracing JIT. Five classic numeric benchmarks
plus a dictionary workload, written identically in both languages. Every runtime
prints identical output; timings are wall clock, best of 3, and exclude the
one-off native build (which is cached).
| benchmark | CPython 3.14 | PyPy (JIT) | Cobra VM | Cobra native |
|---|---|---|---|---|
| n-body, 100k steps | 0.24s | 0.04s | 0.41s | 0.01s |
| binary-trees, depth 15 | 0.71s | 0.12s | 0.60s | 0.12s |
| spectral-norm, n=300 | 0.30s | 0.02s | 0.29s | 0.01s |
| mandelbrot, 1000×1000 | 3.98s | 0.18s | 2.31s | 0.09s |
| word frequency, 300k | 0.09s | 0.03s | 0.07s | 0.03s |
| total (with mandelbrot 400²) | 5.99s | 0.44s | 4.05s | 0.28s |
Native compilation covers Cobra's
type-stable core (functions, structs, collections, loops, math). A program
that uses closures, async, try/catch or
inheritance is reported as not natively compilable β naming what blocks it β and runs
unchanged on the VM, which is itself ahead of CPython here.
The table above is single-threaded. The bigger story is what happens
when work is split across cores: four CPU-bound tasks, run sequentially vs. all at
once. With no GIL, Cobra's async tasks run on every core at once, so
CPU-bound work scales with the number of cores β measured here at ~3.6× speedup
on a tight arithmetic loop, not just overlapped I/O.
One binary, every mode. Compiled .cobrac files are detected
by content, so they run with the plain form too.
| command | what it does |
|---|---|
cobra app.cobra | run a program on the tree-walking engine |
cobra --vm app.cobra | run on the bytecode VM β the fast engine |
cobra --native app.cobra | compile to machine code and run it (cached by source hash) |
cobra / cobra --vm | interactive REPL (multi-line aware, state persists) on either engine |
cobra build app.cobra [out.cobrac] | compile ahead-of-time to a bytecode file |
cobra build --native app.cobra [out] | compile to a standalone native executable |
cobra app.cobrac | run compiled bytecode β no parsing, no compiling |
cobra app.cobra arg1 arg2 | extra arguments reach the program via os.args() |
cobra --ast app.cobra | print the parsed AST instead of running |
cobra --tokens app.cobra | print the raw token stream from the lexer |
cobra lsp | speak the Language Server Protocol over stdio (any LSP editor) |
cobra --version | print the stamped release version |
$ cobra build todo.cobra # compile next to the source wrote todo.cobrac $ cobra build todo.cobra dist/todo # or pick the output path wrote dist/todo $ cobra todo.cobrac :9000 100 # run it β args flow through to os.args() $ cobra --ast todo.cobrac cobra: todo.cobrac is a compiled file; --ast needs source
Source is always the input; you choose the output. Native compilation
reads the source directly β it never goes through .cobrac, because the
type inference it performs needs the syntax tree that bytecode has already
discarded.
| output | how it runs | needs on the target |
|---|---|---|
cobra build app.cobra β .cobrac | bytecode, on the VM | the cobra binary |
cobra build --exe app.cobra | bytecode + VM in one file | nothing |
cobra build --native app.cobra | machine code | nothing |
$ cobra build --native mandelbrot.cobra built native executable mandelbrot $ file mandelbrot mandelbrot: Mach-O 64-bit executable arm64 # ~2 MB, fully static $ ./mandelbrot # no cobra, no runtime, no JIT warm-up
Building a native binary needs the Go
toolchain on the build machine β Cobra uses it as its code generator, the way
other languages use LLVM. Running one needs nothing, and no other Cobra workflow
(running, the REPL, .cobrac, --exe) touches Go at all.
$ make test # static checks + the full ~500-test suite
$ make build # optimized binary for this machine -> dist/cobra
$ make install # build and place cobra on your PATH
$ make release # test, then cross-compile: macOS arm64/amd64,
# linux amd64/arm64, windows amd64 (~7 MB each, static)
$ make bench # the benchmark suite (tree-walker vs VM)
Every snippet below is parsed by Cobra's real parser as part of this page's build check.
let declares, plain = reassigns. Truthiness, operator
precedence and and/or returning the deciding operand all work as you'd expect.
For one-liners there's a C-style ternary, cond ? a : b.
let name = "cobra"
let level = 3
if level > 5 and name != "viper"
print("expert")
elif level > 1
print("getting there")
else
print("new")
end
let tier = level > 1 ? "active" : "idle" # ternary: cond ? a : b
print(tier)
let total = 0
for i in range(1, 11)
if i % 2 == 0
continue
end
total = total + i
end
print(total) # 25 β odd numbers 1..9
while total > 0
total = total - 10
end
First-class functions with real closures β inner functions capture and mutate enclosing variables.
def make_counter()
let count = 0
def inc()
count = count + 1
return count
end
return inc
end
let tick = make_counter()
tick()
tick()
print(tick()) # 3
Reference types with deep equality, negative indexing, insertion-ordered dicts, and familiar method names.
let scores = [70, 95, 80]
scores.sort()
scores.push(60)
print(scores[-1], scores.contains(95)) # 60 true
let ages = {"ada": 36, "alan": 41}
ages["grace"] = 85
print(ages.get("linus", 0)) # 0 β no KeyError surprises
for pair in ages.items()
print(pair[0], pair[1])
end
let log = "2026-06-12 ERROR disk full"
print(log.split(" ")[1]) # ERROR
print(log.upper().startswith("2026")) # true
print(" | ".join(["a", "b", "c"])) # a | b | c
print(" padded ".strip().replace("a", "@"))
init is the constructor, self is implicit, fields are
open. Instances print themselves and type() returns the struct name.
struct Point
def init(x, y)
self.x = x
self.y = y
end
def length()
return self.x * self.x + self.y * self.y
end
def scale(f)
self.x = self.x * f
self.y = self.y * f
end
end
let p = Point(3, 4)
p.scale(2)
print(p) # Point{x: 6, y: 8}
print(p.length(), type(p)) # 100 Point
Throw any value; runtime errors are caught as their message string. Errors unwind
through calls to the nearest handler; finally always runs.
def divide(a, b)
if b == 0
throw {"code": 400, "reason": "division by zero"}
end
return a / b
end
try
divide(1, 0)
catch err
print(err["code"], err["reason"])
finally
print("cleanup always runs")
end
A module is just a file, run once and cached; its top-level names become members.
Native modules (fs, json, β¦) resolve the same way.
import "geometry.cobra" import "geometry.cobra" as geo # cached: same module object print(geometry.circle_area(2)) print(geo.Rect(3, 4).area())
import "fs"
import "json"
let config = json.parse(fs.read("config.json"))
config["retries"] = 3
fs.write("config.json", json.stringify(config, 2))
for line in fs.read_lines("server.log")
if line.contains("ERROR")
print(line)
end
end
import "http"
import "json"
import "re"
let resp = http.get("https://api.github.com/repos/cobra-lang/cobra")
if resp["status"] == 200
let repo = json.parse(resp["body"])
print(repo["stargazers_count"])
end
let emails = re.find_all("\w+@\w+\.\w+", fs.read("contacts.txt"))
print(re.replace("(\w+)-(\w+)", "left-right", "$2-$1"))
@routeRoutes register themselves with a decorator; handlers are plain Cobra functions.
A raised error becomes a 500 and the server keeps running. Requests run in parallel,
so shared state gets a Mutex.
import "http"
import "json"
let routes = {}
def route(method, path)
def register(f) # the decorator: record the route, return f
routes[method + " " + path] = f
return f
end
return register
end
let todos = []
let lock = Mutex()
@route("POST", "/api/todos")
def create(req)
lock.lock()
todos.push(json.parse(req["body"]))
lock.unlock()
return {"status": 201, "body": "created"}
end
@route("GET", "/api/todos")
def list(req)
lock.lock()
let body = json.stringify(todos, 2)
lock.unlock()
return {"status": 200, "body": body,
"headers": {"Content-Type": "application/json"}}
end
def handler(req)
let h = routes.get(req["method"] + " " + req["path"])
if h == null
return {"status": 404, "body": "not found"}
end
return h(req)
end
http.serve(":8080", handler)
Calling an async def returns a task immediately. There is no GIL:
tasks run in parallel across every core, so these three fetches take as long as the
slowest one, not the sum β and CPU-bound tasks get real multi-core speedup too.
Shared state is guarded explicitly with Mutex() and Channel().
import "http"
async def fetch(url)
return http.get(url)["status"]
end
let tasks = [
fetch("https://example.com"),
fetch("https://example.org"),
fetch("https://example.net")
]
for status in await tasks
print(status)
end
try
await fetch("not a url")
catch err
print("caught:", err) # task errors surface at the await
end
Because tasks run in true parallel, shared state needs synchronizing. A
Mutex guards a shared counter; a Channel hands values
from producers to a consumer.
let m = Mutex()
let total = 0
async def add(n)
let i = 0
while i < n
m.lock()
total = total + 1 # read-modify-write β guarded
m.unlock()
i = i + 1
end
end
await [add(1000), add(1000), add(1000)]
print(total) # 3000, every time
let ch = Channel()
async def produce(x)
ch.send(x * x)
end
for i in range(1, 6)
produce(i)
end
let sum = 0
for _ in range(5)
sum = sum + ch.recv()
end
print(sum) # 55
import "proc"
import "net"
let r = proc.shell("git log --oneline | head -3")
print(r["stdout"], r["code"])
let conn = net.connect("example.com:80")
net.send(conn, "HEAD / HTTP/1.0\r\n\r\n")
print(net.recv_line(conn))
net.close(conn)
import "test"
@test.it
def addition()
test.assert_eq(2 + 2, 4)
end
@test.it
def value_equality()
test.assert_eq([1, [2]], [1, [2]]) # deep, like ==
end
let summary = test.run() # prints a report
print(summary["ok"]) # true
A tree-walking evaluator is the readable reference; the bytecode VM is the performance engine. They share one implementation of every value operation, and the test suite requires identical output and identical error messages from both.
Registerized dispatch loop, frames in a preallocated value array (zero allocation per call), eleven fused superinstructions (compare-and-jump loop conditions, compute-and-store assignments, field access), per-VM allocation arenas, small-int interning, and an open-addressing dict with hashes cached on string objects.
The native backend proves one concrete type per variable across the whole
program β a fixpoint over the syntax tree, promoting int to
float the way the language does β then emits unboxed arithmetic and
flat structs. Float operations carry a rounding barrier so the result is
bit-identical to the interpreter's, never merely close.
~500 tests across 12 packages: exact-message error tests, cross-engine equivalence on every example file, live-socket server tests, race-detector runs on the async paths, and benchmarks gated on output equality between the two engines.
Cobra v0.13.0 β one static binary per platform. No installer, no runtime,
no dependencies: download, chmod +x, run.
| platform | file | size | md5 |
|---|---|---|---|
| macOS (Apple Silicon) | cobra-0.13.0-darwin-arm64 | 9.7 MB | 7ad8a7e22afda5cecd8b08483a07ac39 |
| macOS (Intel) | cobra-0.13.0-darwin-amd64 | 7.7 MB | 8dc2ffb9634c7a7201cbe44b32fed190 |
| Linux (x86-64) | cobra-0.13.0-linux-amd64 | 7.5 MB | 5ad5c54949dfcfeb78ccaca140b41ef4 |
| Linux (arm64) | cobra-0.13.0-linux-arm64 | 7.2 MB | 2bda0eb9f0430bb423c263a905fbfe65 |
| Windows (x86-64) | cobra-0.13.0-windows-amd64.exe | 7.7 MB | 0ddea5879df1c5ee2c20f2fe1ecf6dbd |
| VS Code extension | cobra-lang-0.13.0.vsix | 14 KB | 94ec460f4792921fe6adcffcd508beef |
Install the extension with code --install-extension cobra-lang-0.13.0.vsix β
highlighting (including triple-quoted strings and ${β¦} interpolation),
snippets and debugging work once cobra is on your PATH.
All hashes in one file: MD5SUMS.
cobranum β a NumPy-style numeric-array library (dense 1-D/2-D arrays,
vectorized elementwise ops, reductions, broadcasting and linear algebra). On Apple Silicon
it is backed by Accelerate (BLAS/LAPACK) + ARM NEON and beats NumPy on most benchmarks.
π cobranum guide & scientific examples β
| platform | plugin | needs binary | md5 |
|---|---|---|---|
| macOS (Apple Silicon) | cobranum-0.11.1-darwin-arm64.zip | the standard cobra-0.13.0-darwin-arm64 | 065b87bcc172f723ffb52321381b03d0 |
| Linux (x86-64) | cobranum-0.11.0-linux-amd64.zip | cobra-0.11.0-linux-amd64-plugin (glibc β₯ 2.34) | 1afff174c7191edb2cf84e1982150003 |
Unzip to get cobranum.so, put it next to your program (or on the import path),
and import "cobranum.so". See the
cobranum guide for usage and scientific examples.
About the binaries. Cobra plugins are Go plugins: they only load into a
plugin-capable (cgo) cobra binary. The macOS/arm64 release binary is
already plugin-capable, so use it directly. On Linux, the default release binary is fully
static (no plugins), so a separate dynamically-linked plugin binary
(cobra-0.11.0-linux-amd64-plugin) is provided for plugin users. The Linux
plugin pair currently tracks 0.11.0; rebuild against a 0.11.1 plugin binary
(make build && make plugin PLUGIN=./plugins/cobranum) to pick up the
0.11.1 fixes on Linux.
Other platforms (Intel Mac, Linux arm64, Windows): Go plugins cannot be
cross-compiled and are unsupported on Windows, so build from source against your own
cobra β one command, no extra tooling:
$ make build # a plugin-capable cobra binary $ make plugin PLUGIN=./plugins/cobranum # -> cobranum.so $ ./dist/cobra your_program.cobra # with cobranum.so on the path
Dili sΔ±fΔ±rdan, ΓΌretim dΓΌzeyinde anlatan 148 sayfalΔ±k TΓΌrkΓ§e kitap (PDF): temeller, koleksiyonlar, fonksiyonlar, OOP, eΕzamanlΔ±lΔ±k, standart kΓΌtΓΌphane, dilin iΓ§ yapΔ±sΔ± (lexer'dan sanal makineye), yerel makine koduna derleme ve cobranum ile sayΔ±sal hesaplama.
π KitabΔ± indir (PDF, 1.8 MB)
The full 162-page book in English: the language from the ground up β basics, collections, functions, OOP, concurrency, the standard library, the internals (lexer to VM), compiling to native machine code, numerical computing with cobranum, and a web framework and ORM (Venom).
π Download the book (PDF, 1.8 MB)
$ curl -LO https://cobralang.baltavista.com/releases/cobra-0.13.0-darwin-arm64 $ md5 cobra-0.13.0-darwin-arm64 # macOS β on Linux: md5sum $ chmod +x cobra-0.13.0-darwin-arm64 $ sudo mv cobra-0.13.0-darwin-arm64 /usr/local/bin/cobra $ cobra --version cobra 0.13.0
Native compilation, and a substantially faster VM.
cobra build --native app.cobra produces a
standalone machine-code executable β no interpreter, no bytecode, nothing to install
on the target. Whole-program type inference recovers a concrete type for every
variable, then emits unboxed arithmetic and flat structs. On the classic numeric
benchmarks the result beats PyPy's tracing JIT (0.28s vs 0.44s for the suite), with
output verified byte-identical to the VM's. Covers Cobra's type-stable core; a program
using closures, async, try/catch or inheritance
is reported as not natively compilable and runs on the VM as before..cobrac encoding (cobra build --portable):
a flat, little-endian format decodable outside Go, for embedders that execute Cobra
bytecode from another language. Both encodings are auto-detected on load.Bug-fix release hardening the 0.12.0 features after a differential and adversarial review. No breaking changes.
(line 0) for the innermost frame; they now carry the real
line. await failures record the await site, and method frames read the
same bare name on both engines.--vm. The trace is built only
when an error escapes uncaught (~5Γ faster in try/catch loops); an
uncaught throw now carries one too.cobra fmt stops corrupting triple strings. A """β¦"""
value ending in " (or containing """) now falls back to a
normal escaped string instead of re-parsing wrong.""" is an error instead of silently swallowing the
rest of the file.cobra watch no longer leaves a zombie child when the program
exits on its own.${β¦} interpolation.New string and expression syntax, a live-reload runner, richer
time helpers, and call-stack traces for uncaught VM errors. All additive.
"""β¦""". Everything between the triple
quotes is literal: newlines and lone "/"" need no escaping,
so they are ideal for HTML, SQL, or email bodies. Backslash escapes and
${β¦} interpolation still apply, and cobra fmt preserves the
triple-quoted form.+ - * / %, comparisons, and/or,
= and augmented assigns, ., ,, ?,
:, ->) absorbs the next newline, so a long expression can
span lines without parentheses.time helpers. time.year/month/day/hour/minute/second/weekday/yearday(t)
read one component of a timestamp (UTC; weekday is Monday=0), and
time.make(year, month, day[, hour, minute, second]) builds a UTC timestamp
without parsing a string.cobra watch <file>. Re-runs a program
whenever any .cobra file under its directory changes. Dependency-free
(polls modification times), so it behaves the same on every platform.at inner (line 6) β¦) on both the tree-walker and
--vm; a catch still binds the clean line N: message
string, unchanged.Correctness and robustness fixes for the bytecode VM, found by deep differential testing against the tree-walker. No breaking changes.
--vm, a closure that
mutated a captured local (counters, accumulators, bank-account/event-emitter
idioms) updated only its own copy, so the change was invisible to the enclosing scope and
sibling closures β silently wrong results. Captured locals now live in a shared cell
(boxed upvalues), matching the tree-walker.[...]/{...}/Name{...}
instead of overflowing the stack and killing the process.def(x) β¦ end now works
directly inside (...), [...], and {...} β
e.g. map(def(x) β¦ end, xs) β not only as an arrow lambda.def before its
definition ran now reports undefined variable instead of panicking on
--vm.String interpolation, lambdas, multi-value assignment, a source formatter, new standard-library modules, and a NumPy-style numeric-array plugin.
"hi ${expr}". Any expression inside
${β¦}, stringified like print; \$ is a literal
$, and interpolations may nest.def(x) -> x * 2. One-expression lambdas
that work inline (map(def(x) -> x * x, xs)), plus the block form
def(x) β¦ end as a value; both capture their scope.let a, b = 1, 2. Unpack a list or a
return a, b; plain a, b = b, a swaps in one line.cobra fmt. Canonical formatting that preserves comments
and blank lines; -w rewrites in place, --check verifies.encoding, random, crypto.
base64/hex, a seedable RNG, and SHA/HMAC/secure-random.cobranum plugin. A NumPy-style numeric-array library (dense 1-D/2-D
arrays, vectorized elementwise ops, reductions, broadcasting, linear algebra) backed by
Gonum, or Apple Accelerate (BLAS/LAPACK) + ARM NEON when built with cgo on macOS β it
beats NumPy on most benchmarks on Apple Silicon.A module system, augmented assignment, slicing, property setters, and standalone executables.
export + selective from β¦ import.
Modules now export nothing by default; mark a name export to make it public.
from "x" import a, b as c binds selected members directly,
from "x" import * binds them all, and a typo or non-exported name fails at
import time.+= -= *= /= %=. x += 1 updates a
variable, index target (xs[i] += 1) or field (self.n += 1) in place.seq[low:high:step]. Any part may be omitted, negatives count
from the end, a negative step reverses (xs[::-1]), and out-of-range bounds
clamp. Works on lists, strings (rune-based) and ranges (lazy).set name(v) β¦ end. The mirror of get;
runs on p.name = v, ideal for computed fields. Getters and setters are inherited.cobra build --exe. Produces a single
self-contained executable (no runtime or sources needed). --target os/arch
cross-builds for other platforms. --bundle embeds all imported modules into one
.cobrac.VS Code: @test.it snippets and a test-module catalog.
test module members.A built-in unit-test framework and a runtime/memory module.
test framework. Mark a function with @test.it,
assert with assert/assert_eq/assert_neq/assert_raises,
and run them all with test.run(), which prints a report.runtime module. Garbage-collection control and memory accounting
(gc(), mem(), set_gc_percent(), β¦) for profiling and
benchmarking.A ternary conditional operator.
cond ? a : b. Evaluates to a
when cond is truthy, otherwise b; only the chosen branch
runs. Right-associative, so a ? b : c ? d : e means
a ? b : (c ? d : e). It binds looser than or/and
but tighter than =, so x = c ? a : b assigns the chosen value.examples/ternary.cobra.A debugger, native plugins, and stdin input.
cobra dap, a Debug Adapter Protocol server built into the
binary; debugging runs on the tree-walking engine.import "name.so" loads
a native plugin (.so) at runtime, exposing its functions as a module β extend Cobra with
native code without rebuilding the binary. (Linux/macOS; the plugin and binary
must be built with matching versions.)input(prompt?) and read_line()
builtins read a line from stdin (null at end of input).Run File command (βΆ / Ctrl+Alt+N) from
the earlier 0.9.1 extension work. VS Code extension v0.9.3.A source-level debugger.
cobra dap β a Debug Adapter Protocol server built into
the binary; the VS Code extension launches it. Debugging runs on the tree-walking
engine.Cobra: Run File command, or Ctrl+Alt+N, runs it
with cobra in an integrated terminal. (There's no step-debugger, so
F5 still asks for a debug extension β use Run.) The language is unchanged from
0.9.0; binaries rebuilt to stay in step.Higher-order list builtins.
map, filter, reduce β
map(fn, list), filter(fn, list), and
reduce(fn, list, init?) (folds left, fn(acc, elem)).zip, enumerate, any, all β
zip(list, ...) (tuples, truncated to the shortest),
enumerate(list, start?) ([index, value] pairs), and the
truthiness reducers any/all.examples/functional.cobra.Immutable bindings with const.
const NAME = expr declares an immutable binding. Reassigning
it, or redeclaring it with let/const in the same scope,
is an error β caught at compile time on the VM, at runtime on the tree-walker.const xs = [1]
forbids xs = ... but still allows xs.push(2). An inner
scope may shadow an outer const with its own let.struct, const keeps its 0.7.0 meaning β a class
constant.Richer structs: class constants, properties, and static methods.
const NAME = expr β a class constant, read as
Struct.NAME (or through an instance).get name() ... end β a property: accessed like a field,
p.name with no parentheses, it runs with self bound.static def name(...) ... end β a static method, called on the
struct itself with no self.const/static/get are recognized only inside
a struct body, so d.get(...) still works everywhere else. Implemented
on both engines (and compiled bytecode); VS Code extension v0.7.0 highlights them.@route decorators instead of if/elif path
matching β a small registry that keeps the Mutex guarding shared
state under parallel requests. Binaries rebuilt; the language and VS Code
extension are unchanged from 0.6.0.Decorators β @ above a function.
@expr lines above a def
transform or register it: @d binds name = d(name),
@d(args) calls d(args) first. They stack (nearest the
def applies first) and work on async def too.http.serve runs handlers in parallel, the docs and
examples/decorators.cobra show the registration pattern next to the
Mutex its shared state needs.@-decorators and
adds a route snippet.Wait on many channels at once with select.
select() builtin β block until one of several channels
is ready and act on whichever fires first. Each op is a channel (receive) or
[channel, value] (send); it returns {index, value, ok, send}
naming the chosen op. select(ops, default) is the non-blocking form.select.More concurrency tools, and a sturdier runtime under races.
RWMutex() primitive β a readers-writer lock for
read-heavy shared state: many rlock()/runlock() readers
at once, or one exclusive lock()/unlock() writer.ch.try_recv() and
ch.try_send(v) return immediately instead of parking, and
len(ch) reports how many buffered values are waiting.Mutex.)RWMutex and the new channel methods.The GIL is gone β tasks now run with true multi-core parallelism.
async/await keep the same syntax,
but tasks run on every core at once instead of being serialized. CPU-bound work
gets real speedup (~3.7× on a 4-task benchmark), not just I/O overlap.Mutex() primitive β lock() /
unlock() / try_lock() to guard shared state. A
double-unlock is a catchable error, not a crash.Channel() / Channel(n) primitive β
send() / recv() / close() to pass values
between tasks (buffered values drain after close).Mutex.http.serve. Request handlers run concurrently, one
per request, and guard shared state the same way.Mutex, Channel and async/await.async / await concurrency: calling an
async def returns a task; await a task or a list of
tasks to gather results in order. Errors surface at the await site.fs, math, os, json,
time, re, http, proc,
net).cobra build to bytecode, an LSP
server, and a VS Code extension.