-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nim Roadmap 2025 and beyond #556
Comments
Sad to read that. Why not have some kind of "legacy" mode for code that can't be updated? All Also, wouldn't it be possible to automatically convert most To me, code correctness seems more important than being backwards-compatible with old, unmaintained code. I also believe that a strong focus on correctness would be better for the growth of the Nim ecosystem (see Rust). I'd love something that is focused on correctness as Rust, but is as expressive as Nim. Obviously, there would need to be compromises, but having Nil in regular code just for backwards-compatibility shouldn't be one. |
Sure but we need to be able to write code that works with all sort of Nim versions and my proposed way accomplishes that. Changing the default via a mode-switch will come too, but it is much harder to pull off in practice, mostly for bootstrapping reasons. |
And is it the goal to have Nil-safety as the default in the long run? I think, most of the benefits of such features are only gained if they are the default. For example, pattern matching can be implemented in libraries in Nim, but because pattern matching isn't used by a significant amount of the ecosystem, it's not remotely as useful as in languages that have it natively. |
Yes, sure. |
For legacy code couldn't we default to |
I think we continue to need |
Could you expand on that ? I assume this is related to #380 . Do you have an idea of which form it's going to take |
It's already available via |
That's fantastic. I observe Nim already for more than 5 years, and really love many things about it. Unfortunately, there are also a few reasons why I don't use it at the moment. It seems, most of these issues will be addressed in the near future, which is great. For me the ideal situation would be Nim + more compile-time guarantees + sum types + pattern matching + better tooling (which all seems to be planned) + an ergonomic (ideally, automatic) way to use Rust libraries. With the new architecture described above, is there any realistic chance that there will be a new backend that targets the Rust compiler? If not, is there any chance that Nim will natively support (crABI is basically a proposal for a new ABI for languages with nice type systems). Making Rust libraries natively usable would solve one of the biggest issues Nim currently has (there are not many libraries). To me, it seems, Rust is the only option that offers this opportunity. It is compiled, type-safe, has many libraries, has a build tool that basically all Rust projects use (so should be relatively easy to integrate automatically) - I don't think there is anything else that has all of these properties. I'm sure, I'm not the only one in the Rust community who would absolutely love to use Nim and leverage the Rust ecosystem. |
See also https://github.com/arnetheduck/nbindgen/ - this is mostly seamless for our usage of rust using the "old world" C FFI support - crABI would make a few things a little bit more smooth but it is by no means a blocker. For compiler-level interop, there's https://github.com/arnetheduck/nlvm which lets you do cross-language LTO between nim and rust (and anything else llvm-based) - this is better than crABI in many aspects, ie basically it's using the LLVM IR as ABI interop layer and can deduce many of the things crABI encodes). |
I've been watching progress in the Mojo language and I'm curious about spport for ASAP destruction in a future Nim. How much harder is it to destroy at last usage? What are thoughts on the reported benefits of ASAP destruction over scope based RAII? |
Hard real-time apps aren't my area of expertise, but wouldn't you want destruction to be predictable and planned in those cases since it occupies a core? This seems like it would share some of the issues of mark-and-sweep in such apps. Maybe destruction could be ASAP unless there's an explicit call to delete(?) |
Not much harder but I have never implemented it so I could be wrong. Also, the resulting edge cases make me a bit nervous...
Seems like a natural extension but the benefit is marginal for Nim which already has fine grained scopes. Things are different for Python/Mojo where the benefit is larger as Python's scoping rules are terrible. |
Compiling Nim or NIFC to Rust seems to be very hard and unrealistic. Instead there should be a NIFC to LLVM translation step, much like nlvm does it today. That said, I'm more interested in interop with Python than with Rust for the time being. |
I was more interested in the reported benefits with respect to tail recursion and various move optimizations. Yeah Python scoping rules have always been bad. I wish Guido had copied Scheme, or Pascal, which Scheme copied. |
Well Nim does elide wasMoved+destroy pairs so it's quite comparable and should also enable more tail recursions. But tail recursion should have a dedicated syntax as relying on it as an "optimization" is too subtle, in my personal opinion. In fact, using recursion for everything is a "principle of least power" violation. Having said that, Mojo's way of doing it might even be simpler to implement than Nim's wasMoved+destroy elision so I'm taking a closer look... |
There has been a significant amount of work done to remove copies, use moves instead and also remove useless initialization (
I agree. And it would allow using them in Nim in debug-mode without running afoul of the 2000 stacktrace recursion limit. |
Well the compiler follows the spec, https://nim-lang.org/docs/destructors.html#rewrite-rules but there is also |
I agree and would welcome a keyword for explicitly introducing tail call optimization. I'll say TCO rather than "recursion " because IMO most tail self recursions can be written better as loops, and the optimization becomes more valuable when we have mutual (tail) recursion. |
NOTE: This plan covers 2025 and beyond as it is very ambitious.
Nil/not nil
The plan for this feature changed again and it is now:
ref/ptr T
: Remains to be unchecked so that it is backwards compatible with every Nim version ever released. But eventually this will be written asunchecked ref/ptr T
.ref/ptr T not nil
: Checked at compile-time (we need to fix the bugs in the implementation).nil ref/ptr T
: Can be nil and it is checked at compile-time that every deref operation is within a guard likeif x != nil
.This feature is not scheduled for any particular release.
Version 2.4
Version 3
Version 3 will be achieved via a combination of compiler phase rewrites, code reuse, refactorings and porting of compiler code. The primary goal is to finally give us a Nim that offers:
and other
=hooks
can be invoked before they have been synthesized successfullywhich is hard for users to understand.
Implementation
The implementation will use NIF for everything: It is the data format used for communication between the different compiler phases.
Internally most (if not all) phases work on streams of NIF tokens, no tree constructions are required. It is expected that this reduces the amount of memory allocations the compiler has to perform by an order of magnitude.
Arguably a token stream enforces a principled approach to compiler development where by design subtrees cannot be forgotten to be traversed and handled. Roughly a NIF token corresponds to a
PNode
in the old compiler. A NIF token takes 8 bytes in total, aPNode
of today's compiler takes 40 bytes. Therefore it is expected that the new compiler takes 5 times less memory than the current compiler. Since precompiled modules are loaded lazily, this factor should be even higher.The phases of compilation are:
new
and+
to "compiler procs" (lowerer).These phases have been collected into different tools with dedicated names.
NIF
NIF is a general purpose text format designed for compiler construction. Think of it as a "JSON for compilers". NIF has a short precise specification and a Nim library implementation.
While NIF is almost a classical Lisp, it innovates in these aspects:
Status: Implemented in 2024. No further changes anticipated.
Nifler
The Nifler tool encapsulates the initial Nim-to-NIF translation step and is generally useful for other tools that want to process Nim code without importing the Nim compiler as a library.
Nifler can also evaluate Nim's configuration system, the
nim.cfg
files and the NimScript files so that tools likenimsuggest
get precise--path
information and configuration settings without having to import the Nim compiler as a library.Status: Implemented in 2024. Minor adjustments required.
Nimony
The primary point of Nifler is to shield "Nimony" from Nim's compiler internals. Nimony is a new frontend for Nim, designed from day one for:
which work much more reliably since generics and macros are type-checked too.
Status: In heavy development.
Lowerer
The lowerer's job is to "lower" high level Nim code to low level Nim code that does not use features such as closures, iterators and automatic memory management. It is planned to only support Nim's ARC/ORC scheme of doing memory management. In the old compiler ARC/ORC was very complex to support as the problem was not as well understood as it is now: A key insight here is to split up the tasks into multiple well-defined subtasks:
while (;let tmp = f(); tmp.value)
.if
andcase
do not produce values anymore.=destroy(x)
calls at scope exists.As previously mentioned, the lowerer also does:
Status: In heavy development.
Expander
The expander ("Gear 3") performs backend tasks that need to operate on multiple NIF files at once:
until no foreign symbols are left.
importc
'ed symbols are replaced by their.c
variants.importc
'ed symbols might lead to(incl "file.h")
injections.Status: Implemented in 2024. Major adjustments expected.
NIFC: C/C++ Backends based on NIF
NIFC is a dialect of NIF designed to be very close to C. Its benefits are:
between
array
which is always a value type,ptr
which always points to asingle element and
aptr
which points to an array of elements.rule that is concerned with aliasings between a struct and its first element.
Status: Implemented in 2024. Bugfixes required.
The text was updated successfully, but these errors were encountered: