> it is a garbage collected language
GC has to be explicitly attached to types. By default everything is a value type allocated on the stack, and managed by scope. Nim is also clever enough to optimise away copies for value types (such as passing immutable parameters). GC is only really used for reference semantics.
> garbage collection is not really optional
Sure it is. Some of the stdlib uses GC for dynamic lists, but if you're after ultimate control you can easily make your own dynamic lists using manual memory management thanks to the type system and move semantics.
> ARC will still leak memory when there are cycles, so it can work if you are very careful about how you manage data.
If you have cycles and want GC, as you mention, you'd use ORC. As a point of comparison, Rust references also leak with cycles https://doc.rust-lang.org/book/ch15-06-reference-cycles.html
> But it's trickier than what you get out of modern C++, and more resource-hungry than full manual memory management, so I can't really see this option being ideal for gamedev or embedded.
I'm curious how ARC/ORC are tricky to use? Currently it's just a compile switch (soon to become default). There's not really any 'usage' at all, it just switches assignment to move semantics where possible.
> I can't really see this option being ideal for gamedev or embedded.
My personal experience is that ARC/ORC are extremely performant. They don't "stop the world" like Java/Python and are designed to be suitable for embedded work.
In particular ARC offers "deterministic performance for hard realtime systems". For ORC and other GCs you can manually step collection and define soft-realtime collection pause limits. You can even plug in other GC implementations, or create your own if you have specific requirements.
The memory model https://nim-lang.org/docs/gc.html states:
Nim provides multiple paradigms for needs ranging from large multi-threaded applications, to games, hard realtime systems and small microcontrollers.
As an example of a large and complex project running on embedded and using GC, see the Nimbus Ethereum client. Embedded is actually a big use case for Nim specifically because of how memory and CPU efficient the language can be, and how tunable everything is.
Besides, generating a lot of garbage each frame is a design issue in gamedev. Normally you'd preallocate or at least chunk allocate.
> ORC is basically just Python's garbage collection algorithm
ARC is more similar to Rust's move semantics or C++'s smart pointers, and ORC just adds a cycle collector on top. You can also mark types as `acyclic` to remove cycle collection by type.
What makes it ideal for gamedev is high productivity, run time execution speed, interfacing with C/C++ natively, and tools like AST macros.
> For shell scripting, at the end of the day, it is still a statically typed, compiled language. This just doesn't hit the sweet spot for a scripting language ... the entire operating context is irredeemably weakly typed, and nothing you do will ever grow large enough for static types to help much with maintainability.
I think scripting being "irredeemably weakly typed" is a matter of opinion. With good type inference, you get almost all of the advantages of dynamic types, such as fast edit-test cycles, without the pain of not knowing what anything is. Weak typing is ultimately just how you define converters, and I prefer making that explicit rather than lenient (libraries can make typing effectively 'weaker', e.g., https://nim-lang.org/docs/lenientops.html ).
There's nothing you can't do in statically typed languages that you can in dynamically typed languages. The only disadvantage Nim has over, say, Python, is it's weaker REPL support for now (hot code reloading is WIP: https://nim-lang.org/docs/hcr.html ).
The nimscript subset of the language available at compile time is actually really good for scripting on its own, and is used for scripting builds without needing a separate language: https://nim-lang.org/docs/nims.html