Every demo in jsrc/ has a twin in rust/examples/ with the same base name, written to
read line-for-line alike. The two print byte-identical output, so diff is a test:
scala-cli run jsrc/bigcalc.sc > scala.out
cargo build --manifest-path rust/Cargo.toml --example bigcalc
rust/target/debug/examples/bigcalc > rust.out
diff scala.out rust.out # expect no outputOn Windows, run the built executable rather than cargo run when redirecting: cargo's
output plumbing can swallow blank lines, which shows up as a spurious diff.
The nine test-data/*-parity/ fixtures pin one method at a time against recorded
values. That leaves two gaps a demo closes:
- A method with no fixture row is pinned by nothing. The first
pairProberun caughtcanRead/canExecuteansweringfalsefor every directory on Windows, and amkdirsthat threw on one side — neither had a fixture. - Sequences are pinned by nothing. Composition is where ports drift: each call agrees,
the pipeline does not.
forecastchains seeded random numbers → CSV text →loadMatBig→ three estimators; any single-step divergence changes the final line.
They also serve as documentation that cannot rot, because CI-adjacent verification fails the moment a doc example stops matching reality.
| pair | demonstrates | portability of the output |
|---|---|---|
pairProbe |
~50 metadata and mutation operations on identical trees: existence and permission predicates, timestamps, copy/rename/delete collision answers and status codes, write/read round trips | same machine |
treestat |
a genuinely useful tool: recursive walk with pathsTree, immediate listings (paths/subdirs/subfiles), size aggregation by extension, age buckets, digests of the largest file (hash64, cksum, md5, sha256), deterministic sampling, CSV round trip with delimiter detection, and the whole eachArg cursor family |
same machine |
pathshow |
the conversion layer: posx/localpath/dospath/noDrive/relpath/stdpath/posix, segments/baseName/ext/reversePath, mount-table resolution of /c/… and /usr/…, tilde and dot expansion, drive-relative C:/C:foo, the BadPath family, isSameFile, and the String extensions |
same machine |
datecalc |
the date surface: parseDateSmart (with the month-first/day-first split), quikDate/quikDateTime, pattern formatting, field accessors, epoch-day round trips, calendar helpers and month-end clamping, the plus*/minus* and with* families, the between/duration family, getMillis/epoch2DateTime, the BadDate sentinel absorbing arithmetic |
any machine, any day |
bigcalc |
the decimal surface, framed as an exact-money invoice: parse/toPlainString, str2num/isNumeric, arithmetic through the operator overloads, sqrt, integer and fractional pow, all seven rounding modes plus round(MathContext), numStr/numStrPct variants, and the BigNaN sentinel |
any machine |
matdcalc |
the MatD core on one seeded 4×3 matrix: creation, views and gathers, broadcasting, reductions and axis reductions, the pinned matmulPure, masks and where, exact inverse/determinant/solve, svd, pandas-style sort/argsort/percentile/rolling/diff/nlargest, stacking, CSV text |
any machine |
forecast |
numerics end to end: seeded randn → CSV written through Big's rendering (the files match byte for byte too) → loadMatBig → tprfClosedForm, plsClosedForm, pls1Fit, and forecast3prf in-sample and both OOS procedures |
same machine |
Determinism is designed in, not hoped for:
- Every float prints through
Big+numStr, whose rendering is itself fixture-pinned, so no platform's float formatting can leak into the comparison. - Ages measure against a date (midnight), never an instant, so two runs on the same day agree.
- Listings sort on the root-relative path, since neither
Files.walknorread_dirpromises sibling order. - Sampling is seeded —
NumPyRngreproducesuni.data.NumPyRNGdraw for draw. - Fixed inputs in
datecalcandbigcalc(no filesystem, no clock) make those two portable across machines and time, so they work as acceptance tests anywhere.
canRead/canExecutereportingfalsefor directories on Windowsmkdirsthrowing on one side where the other returnedfalseUPath::is_absoluteapplying the Windows root rule under POSIX rules, which madeto_absoluteprefix the working directory twice (found on the first Linux run)- a fixture row that had pinned NTFS directory-enumeration order as if it were API
"OOS CV"not being a procedure name — identically in both languages, which is its own small parity testimonial- two real API divergences, since fixed rather than documented:
sqrtof a negative and a negativepowexponent now answerBigNaNin both languages (Scala used to throw), and those rows are pinned - an incoherence in
isNumeric, which rejected$1,234.56whilestr2numparsed it happily — now one delegated definition
- Write the Scala half in
jsrc/, with the run recipe and the feature list in a header comment. Shadowprintlninside the object (def println(s: String = ""): Unit = print(s"$s\n")) so no carriage returns reach the output. - Write the Rust twin in
rust/examples/, mirroring statement for statement — the shared API is camelCase on both sides precisely so this stays mechanical. - Make any floating-point output go through
numStr, and remove every other source of run-to-run variation. diffthe two. Then keep them diffing: a pair that is never run is a pair that is already wrong.