It seems this is a step into the right direction and closes the gap to Rust in some points.
How are "compile-time reflection" and "contracts" compareable with features in Nimony.
My AI said this:
Nimony’s NIF plugin system is not just “comparable” to compile-time reflection; for compiler-internal metaprogramming/transforms it is often more direct and practical.
C++26 reflection is an introspection API over language entities. Nimony gives you a typed IR (NIF) + traversal/rewriter primitives that let you inspect and transform program structure with very little machinery.
What makes it strong in practice:
Plugins are wired into semantic pipeline stages (.plugin pragmas, type/module plugin queues) via src/nimony/templates.nim, src/nimony/sem.nim, src/nimony/module_plugins.nim, src/nimony/semos.nim.
So compared to C++ reflection:
C++26: standardized compile-time query model.
Nimony: compiler-native query + rewrite model over NIF, with very low ceremony. That’s why your “ridiculously simple and powerful” characterization is accurate.
Nimony does have contract concepts in IR and analysis:
Tags/pragmas include (requires X), (ensures X), (assert X), (assume X) in doc/tags.md. Dedicated analysis pass: analyzeContracts in src/nimony/contracts.nim (plus NJVL counterpart), proving/disproving conditions via fact/dataflow inference.
Important nuance:
This is primarily a static analysis/proof-style system integrated with compiler IR. It is not the same emphasis as C++ contracts’ standardized runtime-checking modes/tooling expectations. Nimony also blends in nilability/effect-like checks (notnil/nil, .raises, borrow-related checks in NJVL path), so it’s broader than just pre/postconditions.
Bottom line
Reflection: Nimony’s plugin+NIF traversal/rewriter model is already a very strong answer, often more powerful for whole-program/compiler-phase transformations than what C++ reflection is targeting.
Contracts: Nimony has real contract primitives and analysis, but with a different center of gravity: IR-level static reasoning rather than primarily standardized runtime contract instrumentation.
And Wirth never did: sum types, async, threading, generics, inlining across module boundaries,
ada picked up from wirth and did do most of those things (threading as a core primitive, shared generics which most languages still don't do.) most of the current "safe programming" push is just rediscovering that ada was essentially correct.
async
delimited continuations from 1988; only took them 40 years.
they needed to rip off the original c syntax bandaid decades ago. let the existing gcc frontends of the time read the legacy code and auto-refactor to a cleaner, LR-compatible update. the refactoring browser guys from smalltalk already demonstrated this kind of thing (some of it survives as SMACC in pharo.)
the tooling has been severely held back for long periods of time due to the marriage of bad syntax choices requiring half an entire compiler just to reason about the basic structure of the program, and the template language being an admitted embarrassment (it would almost be less cursed to just throw it out and staple idris on top of c++ by this point.)
i will never have nice things to say about c++. i am biased.
Ada didn't keep Pascal's (Oberon's etc) parsing speed. And when I tried to use its generics for abstracting over "Pixel size" I couldn't get it to work and used my own custom preprocessor instead. With C++ templates it wouldn't have been any issue. Not to mention details like "you write array(0..4, int) and then some explicit
procedure Set_Main is new Set (T => Integer, X => Main);
Unusable for C++'s STL.
Delimited continuations ... none of Wirth's languages offer these and neither does Ada. What is the point of listing old features that the Pascal-like languages ignored just like the C-likes did?
i will never have nice things to say about c++. i am biased.
Well being biased is fine but you are also wrong. ;-)