5 ms·
Another option is to gradually replace parts of the C++ with Nim code set to output to C++. As such you get the advantages of a high level, low friction languag
by arc619 6y ago
Another option is to gradually replace parts of the C++ with Nim code set to output to C++. As such you get the advantages of a high level, low friction language with fast compile times and move semantics, ABI compatibility with C++, and a really nice FFI. You can import or export functions and so on between the languages, use any C++ libraries in Nim (or visa versa), and even directly emit C++ from Nim if required.
Gradually porting like this lets you keep using your code base whilst introducing new or overly complex stuff in a language that's faster and easier to write (usually ends up with less than half the LoC of the equivalent C++ but often way, way less than that). Metaprogramming is also very nice, easier to reason about and perhaps most importantly, even with lots of macros doesn't noticeably affect the fast compiles.
Another advantage is once you have some Nim code you can choose to change the target to C or ObjC (or even JS or LLVM) so you're actually increasing portability.
This all depends on how you rank 'maturity' of course. Nim's been around for longer than Rust and Go IIRC, and it's been rock solid for me but you may have different parameters. It certainly helps being able to directly use libraries for C and C++ if you can't find an appropriate Nim implementation.
Edit: For contrast, consider the challenges in the article for variants in C++, then the equivilent object variants in Nim:
type
MyVarKind = enum mvkNumber, mvkString
MyVariant = object
case kind: MyVarKind
of mvkNumber:
num: int
of mvkString:
str: string
var myVariant = MyVariant(kind: mvkNumber)
myVariant.num = 1
myVariant.str = "Oops" # Error: 'str' is not accessible using discriminant 'kind' of type 'MyVariant'
- FpUser 6y agoHow do you deal with debugging?
- arc619 6y agoIn VSCode and Neovim there's a visual debugger but in general you can compile with `--debugger:native` and use GDB, for example: A guide to debugging and profiling: https://nim-lang.org/blog/2017/10/02/documenting-profiling-and-debugging-nim-code.html https://nim-lang.org/blog/2017/10/02/documenting-profiling-a... Guide for working directly with GDB-Nim: https://internet-of-tomohiro.netlify.app/nim/gdb.en.html https://internet-of-tomohiro.netlify.app/nim/gdb.en.html A walk through and extra info with the language devs: https://www.youtube.com/watch?v=DmYOPkI_LzU https://www.youtube.com/watch?v=DmYOPkI_LzU
- FartyMcFarter 6y agoBut would you then be debugging the automatically-generated C++ code, which is presumably harder to read than the original Nim source code?
- arc619 6y agoTechnically yes, but directives are inserted so GDB reports the line number, source code, and parameters of the Nim file. However GDB shows the name mangling suffix in generated code, and types are their native types. There's a script called nim-gdb to add pretty printers for types to the GDB output to show the Nim source types. Perhaps surprisingly though, the C and C++ generated output itself is fairly straightforward, even with name mangling suffixes. The inserted directives tell you the Nim source line so you can navigate it fairly well if you want to, and the suffix means the variable is unique referenced in the code. As far as I know you can use any debugger that supports the target language, though I've not tried anything but GDB myself. It's very rare for me to dig into the generated code but sometimes I'm curious about the data structure analog in the target language. In the case of Nim's object variants, last time I looked when compiling to C they were ultimately reduced to simple checked union types.
- FpUser 6y agoLooks more or less workable but I guess not as good as what you get in Visual Studio
- arc619 6y agoNot yet, no. I hope with companies like JetBrains working on their Nim plugin https://plugins.jetbrains.com/plugin/15128-nim https://plugins.jetbrains.com/plugin/15128-nim we'll see more focus put on a smooth IDE based debugging experience in particular.
- deleted 6y ago[deleted]
- vips7L 6y agoWhen compiling to C++ does nim use a GC?
- arc619 6y agoYes, if the target is C++ then the whole output will be in C++, including code for GC operations, so you can directly inspect how this is translated. You can actually choose between several GCs for different needs: https://nim-lang.org/docs/gc.html https://nim-lang.org/docs/gc.html It's worth mentioning that by default all types in Nim are stack allocated, and you have full manual memory management to the same level as C/C++ but with better type safety and less boilerplate. The GC is only used when you tag a type as `ref`, in strings, and the 'vector' dynamic list type, `seq`. The newer GC, ARC (not related to Swift's ARC), is similar to RAII - scope based, non-atomic, deterministic, shares memory between threads but not stop-the-world, and uses move semantics: https://nim-lang.org/docs/destructors.html https://nim-lang.org/docs/destructors.html This makes the GC a nice to use addition for resource management but not a fundamental requirement or speed limitation. In my experience the default (thread-local refc + cycle collection) GC is very performant already, but it's straightforward to write code that works entirely on the stack, or create objects that wrap manual heap allocs, or use custom external memory allocators. Passing `--gc:none` removes the GC entirely from the compilation target, for example if you're working with very constrained embedded devices with the caveat that less of the stdlib is available (currently). The ARC GC (doesn't handle cycles unlike it's sibling ORC) is aiming to be lean enough to be used in hard realtime and memory constrained embedded systems. For hard realtime though I'd expect most people would just manually manage their types anyway on the heap or stack. If you're doing interop between Nim and C++ and want Nim's GC to manage types that you're passing directly to pure C++ code, you can tell the GC that the data is still being used with GC_Ref() or not with GC_Unref(). There are a few libraries for C/C++ interop, such as: https://github.com/nimterop/nimterop https://github.com/nimterop/nimterop Personally in this case I would probably just manually allocate memory memory in Nim or C++ and not use GC'd types across boundaries for clarity if nothing else, still it's an option if your design requires it. Finally, there is a tool to help auto-translate C/C++ to Nim with the c2nim tool: https://github.com/nim-lang/c2nim https://github.com/nim-lang/c2nim and docs: https://github.com/nim-lang/c2nim/blob/master/doc/c2nim.rst https://github.com/nim-lang/c2nim/blob/master/doc/c2nim.rst