Since most posts here are basically about what people don't like (me included) and questions about things that don't work, I would like to ask, what you like the most about Nim. What is the reasons you believe in Nim. Or simply what part of the language or the standard library do you think is the most useful to you, and why.
So I would like to start:
Combination of typed and untyped macros, because the untyped macros give a lot of freedom to design a DSL (domain specific language). The untyped macro can transform the dsl into an expression that is compatible with the type checker, so that a typed macro can process it.
My example is Tensor Contractions in Einstein notation. For those who don't know what a Tensor is, it is Basically a Matrix, just that it can have arbitrary amount of dimensions, meaning it can be 2×3 or 2×3×4 or even 1000×1000×1000×1000. A Tensor contraction is like a Matrix product, best if you just look it up on Wikipedia, instead of me explaining it.
So when I want nim to understand Tensor contractions, I could write a macro that can transform tensor contraction language into loops that then execute the contraction. To do so there are some macro expansion stages.
Stage 1, the the DSL written by the user.
untypedMacroCall:
C[i,l] = A[i,j,k] * B[j,k,l]
the identifiers i j k l were never introduced, this is no problem when untypedMacroCall is an untyped macro.
Stage 2: the intermediate typed macro
the first macro creates this expression:
typedMacroCall:
var C = contract(A,B, [(1,0), (2,1)])
this expression is now valid nim code, where the type checker in infer the types of A and B. A small side node here is, that contract does not really do anything, it is just an empty procedure to make the type checker happy, and pass the expressions to typedMacroCall. This inner macro call can then generate for example loops to do the tensor contraction
var C : Tensor2[A.high(0), B.high(2)]
for i in 0 .. A.high(0):
for l in 0 .. B.high(2):
for j in 0 .. A.high(1):
for k in 0 .. A.high(2):
C[i,j] = A[i,j,k] * B[j,k,l]
The macro could now do some optimizations, for example the loop order. Or when the input is a bit more complex, the macro can detect multiple occurences of the same expression.
Overall I think the macros are a very great language feature, that I would never want to miss anymore in any new programming language that I am going to learn. I don't know any other programming language, where this would be possible.
So what are youre experiences?
Fast / Low memory usage ( compared to competitors ). Compiles to a single binary. Relative clean syntax. Macro support. Hardware support. Flexible.
In other words, all of GoLang its features but better / more flexible / more options / less limitations.
Nim is great because it has this underdog spirit taking on all and everyone, it is down to earth , not overly academic and most of it is fun.
The excitement feels similar to when I was changing from Fortran77 to Turbo Pascal , if I recall that correctly. :P
For me it's allowing to write code compact and looking intuitively, and having many solutions to the same task, at programmer's choice. Something characteristic for Ruby, but even more so for Nim.
Yet its Delphi's roots (which I think gave Nim much of its elegance).
We have override keyword in C++ and @Override annotation in Java, to express our intention of "overriding the base function instead of creating a new base function/overloading/overwriting". That's just stupid: you need to remember not to make mistakes (forget adding override) in order not to make mistakes (accidentally failed to override).
I really like the Nim's {.base.} way of doing this mistake prevention.
I came from a C++ background. There are reasons why people are scared of meta-programming.
I'm quite stubborn when it comes to casing style: no capital letter is allowed in code, not even in strings or comments, except when spelling human names and places (etc) in comments. i.e. I use dash-case whenever possible and fallback to snake_case. That's why I always reinvent wheels or reinvent wrappers becuase libraries just don't agree with my casing style.
In Nim, I can finally stop fighting and write actual codes. I don't need to care what the library author's preference of casing style is and just use my own. Well, not completely since we still have the first letter case-sensitiveness. But that's better than ever before already, and I can bear with that, at least I can insert underscore between word boundaries (HTTPS_ID_Descriptor and HTTP_SID_Descriptor instead of HTTPSIDDescriptor, HttpSidDescriptor and HttpsIdDescriptor). I think it's time for me to go for Bjarne style (Capitalized_snake_case for types and classic_snake_case for the rest).
So I decided to use Nim for my final year school project utilizing WebGL. It must be fun making a DSL that generates GLSL (or just use nimsl?).
LeuGim said:
For me it's allowing to write code compact and looking intuitively, and having many solutions to the same task, at programmer's choice. Something characteristic for Ruby, but even more so for Nim.
Completely agree! I haven't felt so liberated using a programming language since I got started with Ruby. Nim just gets out of your way and allows you to express yourself the way you want. There's no point in a language being safe and efficient unless it is also enjoyable to use. That's why I gave up on Rust after a few weeks and got enticed by Nim instead.