Repository navigation
Releases: alicelanguage/alice
Release list
Alice v1.0.0
-
fix: IL backend async methods and async iterators: a
finally/ensurearound anawaitoryieldran twice when the
continuation resumed the machine on another thread before the suspending MoveNext left the try block (its guard
re-read the state field, which the other thread had set to -1). The guard now reads a MoveNext local set before
each suspension, as C# does with its cachednum. Seen in CI asIl_async_iterator_matches_csharpprinting
"ticks done" three times; pinned deterministically byIl_async_finally_runs_once_when_the_await_resumes_before_the_suspend_returns
andIl_async_iterator_finally_runs_once_when_the_next_MoveNextAsync_races_the_yield. -
fix: dataflow graphs on few cores: an idle node no longer spins while other pool work items wait for a thread, and yields
the core between re-checks instead ofThread.SpinWait. Chains of tiny rings crawled on 1-4 core machines (50k items
through 15 nodes: 8-15 s per run on 1-2 cores, past the 30 s test bound on CI runners), now about 1 s; no wake was
lost. Benchmarks/dataflow unchanged (serial andReplicate). Stress:DataflowStressTests(pinned to two cores). -
tests: Windows CRLF normalization in dump comparisons (ClosureConvertTests, DynSitesTests)
-
tests: Windows file handle leak in CoreFsProcessTests (enumerator disposal)
-
tests: Windows cross-drive path handling in ExecutablesTests (GetRelativePath can return absolute paths)
-
tests: macOS path canonicalization in ProveCliTests (initialize dir from Directory.GetCurrentDirectory() after SetCurrentDirectory to resolve symlinks)
-
tests: allocation test flakes on macOS/Linux (extended warmup in CoreNetAllocationTests to trigger lazy thread-pool initialization)
-
compiler: Windows DLL export declaration (__declspec(dllexport) for @[Native] functions)
-
tests: allocation test flakes on macOS (extended warmup in ParKernelTests to trigger lazy thread-pool initialization)
-
sdk: MSBuild Exec task for alice gen now surfaces compiler output (StandardErrorImportance="high" in Alice.targets)
-
cli: with stdout redirected (MSBuild, CI, pipes) diagnostics are plain text on stderr; the "could not compile" summary names the first error; an
alice gencrash is a canonical MSBuild error line andalice buildshows the command output when MSBuild reports only MSB3073 -
sdk: Alice.targets runs the alice.dll that drives
alice build(AliceRunningCompiler) in the repo layout, falls back to the configuration that exists, and fails with the paths tried when no compiler is found -
tests:
--native-libwithout @[Native] functions writes no C file (no clang on any OS) -
tests:
Echo_with_256_connections_allocates_nothing_per_messagemeasures in a child process and asserts 0 B: the echo allocates nothing; the 0.5-2.4 KB it saw came from the test host (about 1.7 KB/s with no server running) -
fix:
alice gencrashed with BadImageFormatException on Windows (web API sample): a type lookup followed a type forward into a reference assembly (Microsoft.Extensions.Logging.Abstractions). Type lookups now skip assemblies the runtime cannot load, and framework reference packs (ASP.NET Core) resolve to the installed shared framework for reflection -
tests: the allocation tests that read a counter disturbed by other threads (echo, affine tree build, dataflow per item) measure in a child process running nothing else, with a negative check each; all three read exactly 0 B
-
fix: dataflow
Graph.Runno longer allocates 24 B when it has to sleep until the graph finishes (its ManualResetEventSlim created a lock object only then); it waits on a monitor allocated with the graph -
prove:
alice prove --checknow verifies PROOF.cert certificates when present (without needing --smt flag) -
IL backend is the default target (ADR 0033);
--backend csharpflag,[build] backend = "csharp"in alice.toml, andALICE_BACKEND=csharpenvironment variable preserve C# printer access for differential testing and debugging. -
Checkable proof certificates (ADR 0042):
alice prove --smtproduces independently verifiable certificates when a proof-emitting SAT solver (CaDiCaL 1.7+) is available. Each certificate contains the rule's symbolic IR (Alice.Check terms), the Tseitin-encoded CNF, and an LRAT proof from the SAT solver. The standalonealice-checktool (<600 lines, no compiler/runtime dependencies) verifies: (1) the LRAT proof refutes the CNF, (2) the CNF matches the re-derived bit-blast of the IR, (3) hashes match.alice prove --checkre-validates all certificates.PROOF.cert(Brotli-compressed) accompaniesPROOF.al. Trusted computing base for certificate mode: Alice's rule-to-IR translation + alice-check (vs. enumeration: compiler+runtime, --smt without certs: +Z3). docs/proofs.md, alice-check executable, tests/Alice.Check.Tests (46 tests), differential fuzz extended to certificates. -
perf: Bend 2 runtime suite re-measured on Intel Xeon 8488C, .NET 10.0.114, commit 1746ce4 (benchmarks/bend2/results/summary.md). Serial geomean Alice/C 1.54x (16 workloads), parallel speedup 8.8-21.0x on 32 cores; all checksums match C. bend-vs suite unchanged (Bend not available on this machine).
-
core: Alice's own regex engine (ADR 0036,
src/Alice.Runtime/Core/Text/Regex/): Onigmo/Ruby front-end (RegexSyntaxtoRegexNode+RegexFeatures), Tier R = literal prefilters (memchr/SearchValues, Teddy over AVX-512/AVX2, inner literals, ASCII-caseless) + lazy DFA forward and reverse + Pike VM for captures, Tier B = own memoizing backtracker (look-around, backreferences, atomic/possessive, large repeats); UTF-16 and UTF-8 without transcoding; match-only calls allocate nothing. Regex literals are nowAlice.Core.Text.Regexwith Ruby semantics (m= dot-all,^ $line anchors, ASCII\w, named groups turn off unnamed captures,\1templates);=~,match,scan,gsub,sub,splitrun on it and record the last match (Prelude.last_match, lazy). Parity: 100k random patterns against the BCL oracle (Tier R and Tier B) and Tier R against Tier B, 0 divergences (tests/Alice.Tests/Runtime/RegexParityTests.cs). Internal users ofSystem.Text.RegularExpressions(CLI, LSP, REPL, telemetry, compiler passes,expect match,format) run on it too. Forge, pinned: regex-redux 0.83 s on UTF-16 and 0.55 s on UTF-8 vs .NET Compiled 3.98 s and NonBacktracking 4.90 s; rebar-style counts on UTF-8 are faster than Compiled except\p{Lu}\p{Ll}+(0.87-0.92x), and on UTF-16 four rows are 0.78-0.97x with the causes given (benchmarks/core/regex/results.md). Search paths: end-onlyCount, a vectorized start-state skip in the lazy DFA, two-offset literal scans (UTF-16 packed to bytes), exact UTF-16 caseless literals by simple case folding (tests/Alice.Tests/Runtime/RegexScanTests.cs). -
IL optimizer round 2 (IL backend only): loop-carried store-to-load forwarding (
Air/Passes/IlOpt/StoreForward.cs,
switchforward): a load of the element the previous iteration stored reads a register instead of memory, for
fresh non-escaping arrays with one unconditional store per iteration and proven-in-bounds loads (editdist IL / C#
1.00 -> 0.75); forced inlining now bounds the size a body expands to with itsinlinecallees (gameoflife 0.96 ->
0.92). bend2 serial geomean IL / C# 0.96 (0.94 without the arena tree ports), warm and parallel tables in
benchmarks/bend2/results/il-vs-csharp.md. -
IL backend optimizer (il-opt; IL backend only,
ALICE_IL_OPTswitches, e.g.0or-inline,-inbounds): R9
[AggressiveInlining]on small loop-free bodies with at most 3 call sites (never fork dispatchers or__fork_*
helpers); proven-in-bounds array reads and writes (Air/Passes/IlOpt/InBounds.cs: interval analysis over
exact-length local arrays, emitted asGetArrayDataReference+Unsafe.Add, ILVerify clean) and overflow checks
whose exact result interval fits the type removed; peepholes (null tests, constant branches, compare-branch fusion,
type tests in Roslyn'sis T pshape). Wired through main's IL hooks (IlPipeline.AfterLowering/BeforeEncode,
IlBody.IndexLoadExt/IndexStoreExt,IlBuilder.OptimizeExtra). bend2 serial, IL / C# wall geomean 0.98
(1.00 without il-opt; raytrace 1.18 -> 0.98, hashmap 1.03 -> 0.98); the arena tree benchmarks stay at 1.02-1.08.
Table: benchmarks/bend2/results/il-vs-csharp.md; docs/performance.md "IL backend optimizer". -
CM loop shapes (ADR 0039, P2.3): counted loops that are a scan, segmented scan, combine (histogram / scatter-add),
compaction or permutation lower toAlice.Runtime.Cmkernels in both backends (Lowering/Lowerer.Cm.cs, AIR nodes
inMir/MExpr.Cm.cs,Backend/Printer.Cm.cs,Backend/Il/AirToIl.Cm.cs); inferred only where the result equals the
serial loop (wrapping/bitwise integer ops, 16K+ iterations, serial fallback otherwise).cm for/cm ordered for
require a shape (AL0247), float combines needordered(AL0248), permutations a proof (AL0249).alice explain
rows; CM idiomatic programs inbenchmarks/bend2/idiomatic/cm/, results inbenchmarks/bend2/results/cm.md. -
IL backend wiring (backend plan D1.6/D1.8/D1.9/D1.10, ADR 0033):
alice run --backend il/alice emit --ilnow compile async/iterator/async-iterator methods (own state machines,Air/Passes/StateMachines),Anyoperations (Alice.Runtime.Dyncall sites, AL0232), records, struct records and sum types (Synthesize), andlibP/Invokes; the three stub testsIl_async/iterator/async_iterator_matches_csharpare real C#-vs-IL differential tests. Fixes found on the way:breakinsidefor v in <IEnumerable>left the try withbr,String == Stringwas a reference compare under IL. -
IL backend declaration kinds (D1.10): generic classes/methods (by monomorphization, incl. generic base classes), delegate types and method-group values, constant-expression enum members (
B = 1 << 1,AB = A | B), default interface methods, interface properties,@[Stack]stru...
Alice v0.14.0
-
Telemetry ships disabled in this release:
alicenever asks, records or sends, andalice telemetryonly reports
that it is disabled. The opt-in machinery below stays in the code behindTelemetryPolicy.Available. -
Higher-order functions are specialized per lambda literal (ADR 0026):
apply(xs) { |x| x * k }calls a clone of
applywhoseyieldis a direct call of the block body, withkpassed as a parameter. No delegate, no closure
allocation, and the JIT can inline the body (a HOF-heavy benchmark: about 2.3x faster).ALICE_NO_SPECIALIZE=1
turns it off. -
Borrow and lifetime checks (ADR 0027): passing one mutable value twice to a call that writes through one of the
parameters is AL0217 (copy_into(a, a)); a@[Stack]value captured by a block, stored in a heap type's field
or put in a collection is AL0218 (was a C# error at emit time); using a mutable value after sending it through a
Channel/Actoris AL0219; writing a value a runningspawnreads before the task is joined is AL0202. -
Loop interchange and cache tiling (ADR 0025), the
loop-tileMIR pass. It applies to 2-3 deep counted nests over
flat arrays. An affine dependence analysis delinearizesi * n + jand computes direction vectors. Each nest gets
the legal order with stride-1 innermost access (i-j-kmatmul becomesi-k-j). 3-deep nests and transposes are
tiled when every dependence is non-negative. Tiles: 64 for matmul (half of L2), 32 for transpose (half of L1).
ALICE_TILE=noverrides the size. The new nest runs behind a once-per-call guard (in bounds at every corner, no
aliasing between written and read arrays); otherwise the original runs. Results are bit-identical. Checked
integer arithmetic is not reordered.benchmarks/tiling.shmeasures before and after. -
BEAM-style processes (ADR 0028).
Actor(T)is now a supervised, linkable process: a crash kills only that actor,
link/on_exitpropagate exits, andSupervisor.one_for_one/one_for_allrestart children in place with
restart intensity (maxrestarts per window) and nested trees.Actor(S, T).new(init, handler)keeps isolated
state built inside the actor. The mailbox is a lock-free queue and the actor is its own thread-pool work item:
0 bytes per message in steady state, ~6 M msgs/s on one actor and ~11 M msgs/s over 64.
Isolation is compiler-enforced: non-sendable message types are AL0230, actor blocks capturing mutable locals AL0231. -
gpu forlaunches (ADR 0021): explicitly grouped kernels with an occupancy-sized group (a power of two, a multiple
of the warp size) and a capped grid, and a grid-stride loop. Reductions add in registers, reduce per group (warp
shuffles, then shared memory) and do one atomic add per group instead of one per iteration: a 10M Int64 sum on an
Iris Xe (OpenCL) 18 ms -> 4-6 ms. The device accumulator is cached, so a launch allocates nonew T[1]or buffer.
Write-only arrays are not uploaded (only the launch's range comes back), read-only arrays are not copied back, and
a region skips the upload of an array its first loop overwrites whole. -
Opt-in CLI telemetry, disabled for now (ADR 0031, docs/telemetry.md): off by default, asked once on an interactive terminal (never in
CI), and afteralice self updateonly when no answer is stored.alice telemetry on|off|status|show|reset|perf;
ALICE_TELEMETRY_OPTOUT=1/DO_NOT_TRACK=1always win. Command name, versions, OS/arch, exit code, duration,
sanitized crash stacks and error-code counts; never source, paths or names, and never inside compiled programs. The
default endpoint is disabled until a server is deployed.tools/telemetry-serveris a self-hostable collector
(ASP.NET Core + SQLite, strict validation, rate limit, 180-day retention, admin-only aggregates, Dockerfile). -
Stream fusion (ADR 0029):
take(n)fuses into map/select/reject chains (xs.map{}.select{}.take(n).sumis one loop, no intermediate arrays);to_a/mapafter maps and takes write an exact-size array for arrays,s.charsand Int32 ranges; effectful stage blocks are no longer interleaved (an effectful stage before another block, a take or an early-exit sink runs stage by stage, as written); small literal arrays inside an inlined block go to one stack buffer before the loop. -
Tensor primitives in the runtime (ADR 0030):
Tensor<T>(strided, zero-copy views over 64-byte aligned native
memory),TensorArena,BFloat16andHalfconversions,QuantizedMatrix(int8/int4 blocks of 32 with a Half
scale, GGML Q8_0/Q4_0 layout) with fused dequantize-dot,MappedFile(memory-mapped spans and tensors, no copy), and
Nnkernels: dot, GEMV (f32, bf16, Half, int8, int4), tiled parallel GEMM, elementwise, sum/max, fast exp, softmax,
RMS/layer norm, silu/gelu/tanh/relu. AVX-512/AVX2/Vector128/scalar tiers, a persistent allocation-free worker pool,
0 bytes allocated per call. Callable from Alice withusing Alice.Runtime.benchmarks/tensors: GEMV 4096x4096 f32
2.0 ms (naive loop 17.7 ms), int8 0.67 ms, int4 0.59 ms on the 12-thread laptop. -
WebAssembly packages (ADR 0023):
kind = "wasm"in alice.toml,alice new <name> --wasm(page, boot script and an
@[JSExport]example),alice buildpublishes the static site todist/wwwroot, andalice runruns it under
Node.@[JSExport]/@[JSImport] partial defcall between Alice and JavaScript. No workload needed. -
Parallelization soundness fixes (never parallelize unproven code):
forloops writing one array in two index shapes (a[i]anda[i * w + j]), or readinga[i]while writing
a[i * w + j], stay serial; distinct arrays in different shapes get a runtimeReferenceEqualsguard. Before,
iteration 0's row overlapped iteration 1's cell.- A call to an instance method of a class with subclasses is pure only when every override is: a subclass's
field-writing override could run inside a parallel loop or fork. - A loop whose body assigns a branch-declared local (
t = ... if c, read later) stays serial: the local carries
across iterations. Before, the parallel helper did not compile.
-
AL0202 catches races it missed: a spawned/parallel block calling a field-writing method on self (
spawn { bump });
index writes keyed bypar_eachvalues orPar.Range'shi(onlyPar.For/Parallel.For's index and
Par.Range'sloare disjoint, and only when the block does not reassign them); methods that write fields from a
block, or by calling a field-writing method on self, now count as mutating. -
Par.Sumforks by index halves (ParReduce) instead of adding partials under a lock: no lock or closure, and the
same float result on every run.
Archives built from c510b84. Build and package checks: https://github.com/alicelanguage/alice/actions/runs/40546663672
Alice nightly 0.14.1-nightly.20261028
Nightly 0.14.1-nightly.20261028 built from b82a902. Not for production. Install: alice toolchain install nightly. Build: https://github.com/alicelanguage/alice/actions/runs/40667086527
Alice v0.13.1
- Errors that come from the generated C# point at the right Alice column: the name they quote (
frob, orto_widget
for .NET'sToWidget), or the line's first token.#linemaps lines only, so these carried the C# column. - ADR 0022 records
alice prove --smt. alice prove --smtcalls Z3's C API directly instead of the Microsoft.Z3 package (x64-only): it now runs on
Apple Silicon and arm64 Linux, and the CLI has one dependency fewer.findis nilable (T?), as the lowering already produced:if big = xs.find { ... }on numbers is a nil check
instead of a C# error, and null safety applies to its result.
Archives built from b7dc30e. Build and package checks: https://github.com/alicelanguage/alice/actions/runs/39977055637
Alice v0.13.0
alice prove --smt: opt-in Z3 (system libz3 or ALICE_Z3) proves rules over fullx : Int32/x : Int64ranges, with overflow, division by zero and floored/ %semantics; untranslatable rules fall back to enumeration.- Package builds type-check once:
alice genskips its in-process Roslyn check (--no-check) and csc errors are reported as Alice diagnostics. A one-file edit rebuild: 3.7 → 2.2 s.AliceGenCheck=truerestores the old check. - Version 0.13.0. This release was tracked as 0.12.3 until its scope (FFI, NuGet distribution, GPU, Avalonia, EF Core, source generators...) made a minor version the honest number. A bare
alice proveskips nested directories that have their ownalice.toml. - Integration tests delete their temporary projects, feeds and NuGet caches. A full session had filled a 7.7 GB
/tmpRAM disk with 2021 leftover directories, 175 MB per SDK-package run. gpu ... endregions keep the arrays of thegpu forloops inside on the device: each is uploaded once, and written ones are copied back atend. A CPU read inside the region is a compile error. 51 launches over 1M floats: 29 ms in a region against 132 ms with per-launch transfers.gpu forreductions:t += einto an outer Int32/Int64/Float32/Float64 is an atomic add on the device (100k-element Int64 sum, exact on the OpenCL GPU and the CPU accelerator).gpu for i in a...b(ADR 0021): the loop body is compiled to an ILGPU kernel and run on the preferred device. It ran on this machine's OpenCL GPU, with results identical to ILGPU's CPU accelerator, whichALICE_GPU=cpuforces. Admission is thepar forindependence proof plus GPU rules (arrays of numbers and numbers; arithmetic, indexing,Math.*, conversions; no calls, allocation or reductions), each rejection naming its cause. Kernel bodies are unchecked and not FMA-contracted: the device compiler contracts, and an explicitFusedMultiplyAddwas rejected by the OpenCL driver.- GPU kernels in Alice:
examples/gpu/ilgpuruns an Alice module function as an ILGPU kernel on the preferred device (it ran on this machine's OpenCL GPU; CUDA works the same, and ILGPU's CPU accelerator is the fallback). Covered by an integration test. To get there: a method reference to a static method lowers to the method group, not a wrapping lambda (C# caches the delegate, and APIs that need the real method get it); C#-style type argumentsArrayView1D<Float32, Stride1D::Dense>are accepted inside generic calls, with>>split; explicit type arguments work on generic extension methods. - Avalonia UI: an
.axamlwindow with its code-behind in Alice (examples/ui/avalonia, run headless in an integration test). Fixes on the way: the compiler reflected over reference assemblies (NuGetref/, a project'sobj/.../ref/), whose stripped private members crashed type loading (TypeLoadExceptionon Avalonia'sStyledElement), and now reflects over the implementation assemblies, while Roslyn still compiles against the references;src/**/*.axamlareAvaloniaXamlitems in the generated project; extension methods inherited by a .NET base class are callable with implicitself(FindControl<TextBlock>("x")); a capitalized generic call without a receiver parses; and a paren-less member of unknown type standing alone as a statement is a call. - Type-aware references and rename. The language server binds the project and keeps only occurrences resolving to the symbol under the cursor, or to an override of it in the same class hierarchy:
Square#arearenames without touchingInvoice#area. Unresolved code falls back to name matching. - Owned lists and hashes of any element type (
List(String),Dictionary(String, Int32)), not only of numbers. Only the collection must stay local, andClearon release drops element references, so the pool keeps nothing alive. - Class discovery:
Controller.subclasses,Controller.descendantsandObjectSpace.each_object(typeof(Controller)) { |c| }over the program's own classes, which is what a framework needs to find controllers or plugins. Live-object enumeration is not offered: it has no safe .NET equivalent. - Refinements:
refine String do ... endinside a module is a monkey patch visible only in files that writeusing <module>. In C# it is an extension class in namespace__Refine_<module>, imported only by those files, so the scope holds there too. - Forks of three calls in one expression (
trib(n - 1) + trib(n - 2) + trib(n - 3)) via a three-wayPar.Fork:trib(32)335 -> 43 ms on 12 cores. A failing branch's exception surfaces once every branch has finished. - Fix: an assignment inside a branch of a block now assigns the enclosing method's variable, as in Ruby. Before,
h.each { |k, v| best = v if v > best }declared a new block-localbest, and the method'sbestsilently stayed 0. Found while checking the owned-hash benchmark's checksum, which was 0 under the old compiler too. - Owned hashes (ADR 0016 amendment): a local
Dictionary(K, V)of numbers that never escapes is pooled and its buckets reused (benchmarks/gc/hashes.al: 137-146 -> 97-104 ms, 2239 -> 0 MiB, 374 -> 0 gen0 collections).Keys/Valuesviews count as escapes.h.each { |k, v| ... }on a Dictionary is inlined toforeach (var (k, v) in h), with no closure or delegate. - Owned lists (ADR 0016 amendment): a local
List(T)of numbers that never escapes is rented from a per-thread pool and released at its last use, keeping its grown backing array. A scratch list built per call (benchmarks/gc/lists.al, 200k calls) took 59 ms, allocated 2926 MiB and ran 489 gen0 collections; now it takes 31 ms with 0 MiB and 0 collections. Views, spans, enumerators, storing and capturing keep a list on the GC, and a returned list moves out unreleased. - View models for XAML UIs:
event PropertyChanged : PropertyChangedEventHandler(capitalized event names, required to implement .NET interface events) and Ruby's private@countbeside a publicdef count(the field takes another C# name instead of colliding). AnINotifyPropertyChanged+ObservableCollectionview model is tested. - Language server: find references and rename. Matches come from the lexer, so strings and comments are left alone but
#{...}holes are found. Top-level names are renamed across the project and locals within their enclosingdef; an invalid new name is refused. - Incremental package builds:
alice genruns only when a source, the reference or analyzer list, the compiler or the project changed (MSBuildInputs/OutputsonAliceGenerate, with a sources list so that added and deleted files rebuild). A no-opalice buildtakes 1.0 s instead of 2.35 s. Covered by an integration test for no-op, added-file and deleted-file builds. partial def(no body): a declaration a source generator completes, for[GeneratedRegex](regex compiled at build time) and[LibraryImport](.NET's source-generated P/Invoke) next to Alice's ownlib/fun.docs/production.md: what is ready for production, the test behind each claim, recommendedalice.tomlsettings per workload, and the known gaps.- F# consumes Alice libraries built with
naming = "dotnet":Geometry.Distance,IsEmpty, records, and sum types matched with:? Shape.Circle as c -> c.R(Integration/FSharpInteropTests, a real.fsproj). - Roslyn source generators work on Alice code (
[JsonSerializable]contexts for reflection-free, NativeAOT-safe JSON;[GeneratedRegex];[LoggerMessage]; NuGet generators).alice gen's type check now runs the generators MSBuild supplies (@(Analyzer)) instead of failing on members they add, and single-file builds find the framework's generators in the targeting pack. Framework generators load only when their attribute appears: hello world compiles in 1.06 s as before, not the 1.55 s it took with every generator loaded. - Multi-line blocks inside call parentheses parse:
Task.Run(->() {followed by statements on separate lines. The lexer dropped every newline inside(/[, so statements in a nested{ }ran together. It now tracks the innermost bracket. - FFI stress tests (
FfiStressTests): strings at the 85/86-char stack-buffer boundary with 2- and 4-byte UTF-8, lone surrogates (encoded as U+FFFD), 8 threads x 20k concurrent string calls, repeated callback exceptions, and empty and 16 MiB pinned arrays. - Entity Framework Core works from Alice.
examples/data/efcoredefines aDbContextsubclass with anOnConfiguringoverride andDbSetproperties, and runs LINQ queries that EF translates to SQL from the Alice lambdas (WHERE "b"."rating" > 3). It is covered by an integration test. To get there: extension methods from any referenced assembly are callable without parentheses (query.ToQueryString), not only LINQ's;obj.tap { |o| ... }andobj.then { |o| ... }were added; and a multi-statement block passed where anActionis expected drops its tail value. x.try &.m(args)(Crystal): the safe callx&.m(args), no longer "planned".- Lambdas as blocks:
xs.sum(&->sq),xs.select(&->(x : Int32) { x.even? })andxs.map(&f). A lambda literal or method reference passed this way is inlined into the loop like a literal block, with no delegate. - Named tuples:
{name: "ada", age: 36}and the type{min: Int32, max: Int32}are C# named tuples ((string name, int age), no allocation), read witht.nameort[:name], where an unknown element is a compile error. Hashes keep=>. - Assignment as a condition:
if user = find(id)andwhile line = reader.ReadLine. Thewhileform assigns before every test, andelsif x = fevaluatesfonly when the earlier conditions failed. - Flow narrowing for nullable numbers: inside
if nand after a guard clause (return unless n,break/next unless n,raise ... unless n), anInt32?local reads asInt32(n.Value). Narrowing stops where the branch reassigns the local. C# already narrows nullable references. - Co...
Alice v0.12.2
Alice 0.12.2: explicit contracts (pure, safe, par, own and borrow parameters, scope), rules and proofs (RULES.al, alice prove, PROOF.al), the built-in guide for people and AI agents, and faster objects, interop and start-up. Update with alice self update.
Highlights
- Say what you want, the compiler proves it:
pure def,safe def,inline def,par a, b = f(x), g(y),own/borrowparameters andscope ... endlifetime regions. A failed proof is a compile error (AL0210-AL0214) instead of silently slower code. - Rules and proofs:
rule name(x in -1000..1000) ... endinRULES.al;alice provechecks every case and writesPROOF.al;alice prove --checkfails in CI when a rule breaks or the code changed. Alice proves its own numeric semantics this way. - Guide and AI agents:
alice guide [performance|proofs|interop],alice agents [--write], andalice newnow writesAGENTS.mdplus aCLAUDE.mdthat imports it. - Faster without code changes:
fib(n - 1) + fib(n - 2)forks directly; returned arrays are recycled by the caller; immutable constant objects are shared (binary trees: half the allocation of C#);BoolC calls 2.7x faster;alice runcaches compiled programs (1.2 s to 0.13 s for an unchanged file). - See what happened:
alice explain file.allists the optimizations each method received.
Changelog
- Explicit, checked paradigms on top of inference (ADR 0017):
- Effects:
pure def(AL0210) andsafe def(secure execution, no ambient authority, AL0212). - Parallel let:
par a, b = f(x), g(y)(Bend's fork without the recursion rule, AL0211). - Inlining:
inline def.
- Effects:
- Ownership:
ownparameters (the caller moves in).borrowparameters (checked, AL0213).scope ... endlifetime regions (arrays must be owned and are released atend).- In-place
xs = xs.map { }for owned arrays. A 3-stage map over 1MFloat64: 4.0 ms and 3 B per call, against 9.3 ms and 32 MB for hand-written C# loops.
- Owned results (ADR 0016 amendment): an array returned by a method that returns only its own owned local is owned by the caller and recycled.
benchmarks/gcscratch: 3.81 MiB per run down to under 400 B, 0 collections. alice run file.alcaches the compiled image by content hash (~/.cache/alice/run,ALICE_NO_CACHE=1to disable): an unchanged program starts in 0.13 s instead of 1.2 s.- Shared immutable objects:
T.new(constants)of an immutable class whose identity the program never observes is one static instance.benchmarks/gctrees: 68 to 34 MiB per run, half the collections, about 1.35x faster than C# (21.5 vs 28.9 ms). - Interop:
funsignatures over numbers andBoolare blittable (aBoolcrosses as one byte behind an inlined wrapper), with no marshalling stub; aBoolC call is 2.7x faster.@[Fast]on aBoolfunction no longer fails at run time. Imports useExactSpelling. - Rules and proofs:
rule name(x in lo..hi, b : Bool) ... end(RULES.al) declares a pure property over a finite domain.alice provechecks every case and writesPROOF.al, a certificate tied to a hash of the sources.alice prove --checkfails when a rule fails or PROOF.al is stale. Domains over 2^32 cases are AL0214. The repository'sRULES.alproves Alice's numeric semantics;dotnet testchecks it. divmod,tdiv,remainderandmodulocount as pure.alice explain file.al: per method, the optimizations applied (fork/join, parallel loops, owned arrays, in-place maps, shared objects, stack arrays, SIMD, fast native calls).alice guide [performance|proofs|interop]prints the guide fromguide/, embedded in the CLI, for people and AI agents; everyalicecode block in it is compiled by the tests.alice agents [--write]prints or merges an Alice block into a project'sAGENTS.md: workflow, Ruby/Crystal habits that are wrong in Alice, error codes.alice newwritesAGENTS.mdwith that block and aCLAUDE.mdthat imports it (@AGENTS.md).- Tests that run programs in
ExplicitParadigmTestsjoin theconsolecollection. - Fork/join of independent redexes (HVM-style): a statement whose value is a pure arithmetic term with exactly two calls to pure user methods, one recursive, forks the two calls without named results (
fib(n - 1) + fib(n - 2),1 + l.count + r.count). Calls under&&,||,??or?:are never forked, and a fork never captures a nullable local, because the helper would lose flow narrowing. Naivefib(38)on 12 cores: 250 ms -> 145 ms.
Archives built from 35f2433. Build and package checks: https://github.com/alicelanguage/alice/actions/runs/39811840368
Full Changelog: v0.12.1...v0.12.2
Alice v0.12.1
Alice 0.12.1: faster loops over owned arrays and a new GC benchmark. Update with alice self update.
Changelog
- Loops over an owned array bounded by its fixed length (
for k in 0...noverArray(T).new(n)) compare againstbuf.Length, so the JIT removes their bounds checks as it does for C#'snew T[n](ADR 0016 amendment). - README: mutability, ownership, fork/join and benchmark sections.
benchmarks/gc: allocation-heavy workloads (rolling rows, per-call scratch buffers, 4 MiB frames, object trees) in Alice with inferred ownership, Alice with explicitown, and C#, under workstation and server GC. Reports time, allocated bytes, collections, GC pause and peak memory, with charts. Alice runsrowsandframeswith 0 collections (C#: 74-1002) and is about 2x faster than C# onscratchandframesunder server GC.
Full Changelog: v0.12.0...v0.12.1
Alice v0.12.0
Alice 0.12.0 makes numbers exact (floored division, checked overflow), adds a MIR optimizer, ownership for GC-free local buffers, a lean fork/join scheduler, and new syntax: own, par for, unchecked ... end.
Upgrading from 0.11: see What changed in 0.12. Install: curl -fsSL https://alice-lang.org/install.sh | sh or alice self update.
Changelog
-
Breaking (ADR 0013): signed
/and%are floored likedivmod(-7 / 2 == -4);tdiv/remaindertruncate. Float%follows the divisor. -
Breaking (ADR 0013): integer overflow raises
OverflowException;&+ &- &*wrap.2 ** -1raises instead of returning 1. -
Breaking (ADR 0013):
to_u8and the other sized conversions raise when out of range (NaN too);to_X!wraps.2.5.roundis3.0(half away from zero). -
Breaking: floats print with a decimal point and Ruby exponent rules everywhere (
2.0,1.0e-07,1.0e+16). -
Generated programs default to workstation GC (faster startup, lower RSS);
[runtime] gc = "server" | "low-memory"inalice.toml. -
Startup: the
formatregex is source-generated (no Reflection.Emit on every launch); anif/casewith araisebranch no longer becomesdynamic(the C# runtime binder was loading at startup). -
Fix
(-5).absand-7.5.absreturning negative values (the C# emitter dropped the parentheses). -
Fix
round(n)/floor(n)/ceil(n)on decimal fractions (0.29.floor(2)was0.28). -
[a, b, c].min/.maxon a literal lower toMath.Min/Math.Maxwith no array allocation (editdist inner loop). -
Compiler: MIR pass pipeline (ADR 0014) in
src/Alice.Compiler/Optimizer: constant folding, strength reduction (x / 8isx >> 3,x % 16isx & 15with floored semantics), literal[a, b].min/maxwithout allocation, unchecked counted-loop steps.ALICE_DISABLE_PASSESfor A/B runs. -
Compiler: fork/join of independent pure recursive calls (ADR 0015):
a = f(x)/b = f(y)run in parallel with lazy task creation (only the top log2(cores)+3 levels spawn tasks). Writes into arrays allocated in the method keep it pure. Suitetree-radixat 1M elements: 3226 ms → 319 ms (C# 665 ms). -
Breaking:
Channel(T).newis unbuffered (a rendezvous, as in Crystal):sendwaits for a receiver. It was silently unbounded.Channel(T).new(n)buffers n. The channel is a lock-guarded ring (no Task per blocking call, no allocation per message);sendaftercloseraisesClosedChannelError. -
Row flattening: an array of fixed-width literal rows filled by a full
for i in 0...nloop and never escaping (points[i] = [x, y]) is one flat arraypoints[i * k + j]with the column still bounds-checked (suite kmeans at 1M points: 0.44 s / 95 MB → 0.38 s / 63 MB). -
Fix
Array(T).new(n) { |i| ... }ignoring its block. -
Heap-free small arrays: a local array of literal size (<= 256 unmanaged elements, or a literal of <= 32 items) that never escapes lives in one
stackallocbuffer at method entry, also when declared inside a loop. -
Fix
Array(T).new(n, v)ignoringv(it returned zeros); a non-default fill uses an uninitialized allocation plus oneFill. -
Range analysis: counted loops bounded by
.Length/.Countand theiri ± koffsets drop provably dead overflow checks (editdist: 998 → 884 ms, C# 841 ms). -
Stdlib fork/join:
sortof a large primitive array is a parallel merge sort with a pooled buffer (10MInt32: 756 → 207 ms). -
Docs: fork/join (idea credited to Victor Taelin's BendRT) and heap and GC.
-
Value-range analysis: integer
+ - *whose operand ranges (literals, masks, shifts, widened Int32,^/|of non-negatives, floored% d) prove no overflow are emitted unchecked; a provenx >= 2^31 ? x - 2^32 : x(also 8/16 bits) is one sign extension instead of a data-dependent branch. Suite terrain at 1M: 345 → 212 ms (C# 189 ms). -
Purity gate:
Alice.Runtime.Puremarks runtime functions the compiler may parallelize through (Digest::*); staticModule.f(x)receivers, string interpolation, array literals,min/max/sumand the new numeric primitives are pure reads. Suite merkle at 1M leaves: 1812 → 1489 ms (C# 1885 ms). -
Stdlib fork/join:
sum,min,maxof primitive arrays of 2^20+ elements split into SIMD chunks across cores (32MFloat64sum + max: 68.7 → 16.4 ms). -
2.0 ** nlowers toMath.ScaleBandx ** 2tox * x(both bit-identical toMath.Pow); widening conversions (to_i64on Int32,.to_f) are plain casts, narrowing ones an inlined checked helper. -
Fork/join also forks Bend's single-statement parallel call
a, b = f(x), g(y)(pure, independent, recursive), including into existing variables. -
Startup: Prelude's dynamic/reflection/regex caches are created on first use instead of when every program starts.
-
Compiler: a loop nested in a serial loop is no longer auto-parallelized with the "heavy" threshold of 2 (game of life dispatched its 3-cell neighbourhood loop to the thread pool per cell: 197 ms → 60 ms); constant short trip counts emit no parallel path.
-
Fix
for k in 0...mwithm : Int64(andn.timeson Int64) declaring anintcounter that could never reach the bound. -
Allocation-free:
round(n)/floor(n)/ceil(n),q, r = a.divmod(b)(no array),a.step(limit, k)with a literal step (inlined loop), andputs/str/inspectof numbers (no boxing). -
Digest::SHA256.hexdigest,Digest::SHA1,Digest::MD5(Ruby API). -
New primitives:
to_i8..to_u64,to_i32,to_f64,fdiv,sign,popcount,leading_zeros_count,trailing_zeros_count,bit_length,finite?;Int32::MAX,UInt8::MIN,Float64::INFINITY,Float64::NAN; snake_case .NET statics (Math.sqrt,Math.atan2). -
Ownership (ADR 0016): local arrays of unmanaged elements that provably never escape are owned; their buffers return to a per-thread exact-length pool (
Own(T)) before reassignment and at every exit, so a loop building a fresh row per iteration stops allocating. Moves (prev = row), interprocedural borrows and returns keep ownership.own a = ...makes it a checked contract: escape AL0207, use after move AL0208. 12 of the 17 suite workloads use it; editdist RSS 40.7 MB (C# 46.9 MB). -
Auto-parallel loops prove row-major writes disjoint:
img[y * w + x] = ...(directly or through a local bound once) withxcounting0...win a nested loop runs rows across cores, as game of life, mandelbrot and image loops are written. -
Runtime:
Par.Forkoffers its left half as one thread-pool work item instead of aTask(no Task, wrapper closure or continuation per fork); the join runs an unclaimed half inline, spins briefly, then blocks on the job. When the right half throws, the left half finishes before the exception unwinds. -
Syntax:
par for i in a...bparallelizes at any trip count and is compile error AL0209 when iterations are not provably independent;unchecked ... endis a wrapping region for integer+ - *(ADR 0013).alice fmtindents both. -
Benchmarks:
run.shruns Alice with the same server GC as the C# baselines; run 8 recorded (Alice at or ahead of idiomatic C# on all eight). The recursive-kernel rule requires a primitive result, so object-building recursion keeps tier-1 PGO. -
examples/verify.shexpects 0.12 float printing (30.0). -
Version 0.12.0.
-
JIT tiering (ADR 0014): methods with a loop nest, and primitive-only static functions that loops call, compile fully optimized from the first call instead of running instrumented tier-0 code until OSR / delayed tier-up (suite nbody 151 → 78 ms, terrain at 512x512 143 → 115 ms).
-
Parallel loops probe before dispatching: the first two iterations run serially, and the rest goes to the pool only when it projects past the dispatch cost (25 ms cold, 50 us warm); the runtime scheduler samples a chunk the same way. Short loops in short programs no longer pay thread-pool startup (small mandelbrot 80 → 75 ms); large ones stay parallel (4M-pixel mandelbrot 247 → 157 ms vs serial). Parallel chunk bodies compile fully optimized.
-
Floored
/and%by a positive literal are branch-free (floor_div_pos,floor_mod_pos). -
Fix: a loop whose body assigns its own counter is never auto-parallelized.
-
Fix (ADR 0008): a counted loop whose body read the array it writes at another index (
row[j] = row[j - 1] + ...) was auto-parallelized from 65,536 iterations and could compute wrong values. Such loops stay serial; stencils over a different array stay parallel behind a runtimeReferenceEqualsalias check. -
Fix: an exception raised inside an auto-parallelized loop reaches the caller as itself, as in the serial loop, not wrapped in
AggregateException. -
Runtime:
Par.Range/Reduce/MapSumrun on a lean chunk scheduler (ParJob) instead ofParallel.For: one allocation per loop, an atomic chunk counter, and the calling thread works through chunks itself, so nested parallel loops cannot starve the pool and no TPL machinery is JIT-compiled at startup. -
Shift counts are modular (ADR 0013): the
+ - *computingx << ndrop their overflow checks. -
A self-recursive function over primitives and primitive arrays compiles fully optimized from its first call (
AggressiveOptimization). Suite queens: 0.92 s → 0.81 s (C# 0.91 s). -
q, r = 7.divmod(2): multiple assignment destructures arrays and lists. -
Hex and binary literals accept
_separators and type suffixes (0xFFFF_FFFF_i64,0xFF_u8). -
samples/wonderland3d: Alice-authored procedural 3D Wonderland film, interactive preview, deterministic 30-second MP4 export, GLSL bloom and an original synthesized stereo score (ADR 0012). -
Windows installer: launch Microsoft's .NET SDK installer with a child-process execution policy override, preserving the user's policy and reporting SDK installation failures.
-
Root npm commands build/test Alice and generate VSIX/Zed packages from the companion
extensions/checkout.
B...
Alice v0.11.2
Archives built from e7bc3d7. Build and package checks: https://github.com/alicelanguage/alice/actions/runs/38990008774
Full Changelog: v0.11.1...v0.11.2
Alice v0.11.1
Archives built from 1e810eb. Build and package checks: https://github.com/alicelanguage/alice/actions/runs/38988678163
Full Changelog: v0.11.0...v0.11.1