This is really cool. I really want a language that has GC, but lets me be explicit about memory usage as well / leverage move semantics to optimize. I use Rust, and I suspect I'll always have it as a driver, but I wouldn't mind another higher level language to take the place of Python, which I use for prototyping.
Yes garbage-collected, with a caveat. From the website:
> Nim's memory management is deterministic and customizable with destructors and move semantics, inspired by C++ and Rust. It is well-suited for embedded, hard-realtime systems.
The reference counter with "destructors and move semantics..." is not presently the default, though it will be in the future. The OP mentions that.
The current default GC involves a somewhat unusual memory model that can make certain kinds of multi-threaded programming difficult: each thread has its own heap and independent GC; memory subject to GC cannot be read/written across threads and locks can't be used to remedy the situation; if you force the compiler to accept code that violates the "no shared" rule, the ref count of the GC on one thread or another will eventually get corrupted and the program will crash with SIGSEGV.
However, by allocating on and copying to/from the shared heap (which is never subject to garbage collection) you can do message passing across threads.
Note I’m using Nim with the new GC (both ARC & ORC) on dual core esp32’s.
Locks do work with ARC, though some care needs to be taken. Both the Nim and free-rtos multi-threaded queues work well with the correct move/sink annotations.
The design of ARC allows you to move entire memory graphs between separate heaps. It works fine, but what’s not working is the compile time verification that a given memory graph is only owned/aliased by the top pointer. So there’s a lot of work to do in making it “safer and easy” to use.
There’s a few of us working in this area, well rather Nim on embedded microcontrollers. :-)
It works fantastically, though most of us aren’t traditional hard real time folks. Nevertheless Nim’s new ARC is excellent for this area. The overhead of the GC basically is just an increment/decrement on an integer (no atomic). That means it’s fast and predictable for modern MCUs and plays well with C code. If you want a tight interrupt function you can stick an object in global variable and know it won’t incur GC overhead.
It’s relatively easy to reason about where and when you want memory to be free’ed (actually easier than Rust). Also allocator pools are easy to utilize.
On a side note, as the Nim compiler improves moves and sinks analysis, the runtime overhead of ARC approaches that of Rust’s compile time memory management, especially with a lot of Rust code that use lots of Rc wrappers.
P.S. I’m planning to write a Nim wrapper for Zephyr RTOS when I get time later in the summer, and improve the existing FreeRTOS support too.