Very excited for v1.0 -- the solidification of "Concepts" will be quite exciting. The bug fixes and new features in v0.14 are super welcome, definitely looking forward to leveraging the generic type classes fixes: My Either[T] implementation should now work! Exciting stuff.
We've got two internal tools that are written entirely in Nim, and it's been brilliant pretty much all the way through. The rough edges of previous versions are steadily sanded away, and our code becomes more expressive with each version. The biggest thing I'm looking forward to (once v1.0 rolls round) is having the "not nil" specifier be the default for all types. That's going to bring it in line with the other static typing checker we use regularly (Flow) which will be a boon to those of us (mainly me) that live in both worlds most days heh.
It's interesting that the non-null-able stuff is getting into languages just right now.
When using stuff like JS, the possible nulls are a bigger problem than a wrong type in general (still a problem, but IMO not as significant) still systems like TypeScript started without it.
Pretty much the same way you can any other language. GDB/LLDB works fairly well with Nim, but personally I just use a couple `echo` statements when I need to debug anything.
Yup, the source code still appears in GDB and with a bit of tab completion, inspecting variables ain't that hard, either. I've had worse experiences with C code that abused the preprocessor.
Oh yes, I've used it for many years (though many years ago). For me it depends on the size of the program and the compile time; if it's a short one and compiles quickly, I'll throw a print/puts/print/echo in there just to see what's going on.
That's what happens with "real" debuggers, in my experience! Though Codebug (for XDebug in PHP) is what did it for me, but now I'm using interactive debugging wherever I can. Beats the hell out of trying to print out variables.
How do you debug ANY compiled language? Every compiler compiles to another language. ;)
https://en.wikipedia.org/wiki/Compiler
"A compiler is a computer program (or a set of programs) that transforms source code written in a programming language (the source language) into another computer language (the target language), with the latter often having a binary form known as object code."
That's not a good analogy, because C doesn't just compile to assembly in any modern compiler. It compiles to assembly plus DWARF, which is an extremely expressive metalanguage (far beyond #line) for describing the mapping from the generated code back to the source. C has no mechanism for inserting raw DWARF DIEs, while assembly does.
Aside from using GCC's debugging information, you can emit code that creates its own debugging information in some run-time structure.
For example, at the beginning of each function call, you insert a function call that pushes a new stack frame into some global stack, and store the function's arguments. Then, just before every return from the function, you pop the stack frame. When the program crashes, you write the stack to a JSON file, and use a language-specific debugger to view it.
I agree. I don't get it. It seems no one has actually tried it. What I'm asking is what's the idiomatic approach to debugging this. If I code in Nim and produce C code and then compile and link that... I'm debugging produced C code, which is below Nim in the chain. I have to somehow then see what's up with exact Nim code that produced said C code which got compiled and linked. It's two steps remove with a magic, unexplained, step between Nim and C which I'm asking about how to debug.
Javascript targetting languages have source maps to link back errors at the lower level back to the pre-compiled source. Clojure dealt with the dual nature of errors (clojure exception from java exception) by partitioning messages in sub-groups to facilitates reading.
That happens a lot on HN and it is frustrating. It's clear that people have just the barest of experiences with a topic and then speak with authority, to the detriment of others. I try not to comment on things I don't know about and if I do, then I make it clear that I am extrapolating and don't try to come off like an expert because I can google a topic.
GCC supports some special pragmas that Nim puts in the generated code. It then transparently maps the Nim source to the compiled instructions. This is exactly like JS sourcemaps for languages that compile to JavaScript. I haven't tried it that much, but it seems to work pretty well.
To be honest, I never managed to get familiar with many debuggers in a fashion that I could use them productively, except for Microsoft's Visual Studio tools (VC++, good ol' VB6 :-)). I know enough GDB to survive, and from what I've seen Nim works there almost just as well as plain C code.
There was a special debugger for Nim that worked by inserting instrumentation code during compilation, but that seems to have been deprecated.
There are several languages similar to Nim these days, and they're all very exciting. For example, Nim, Rust, D, Go, and probably others I'm forgetting. Does anyone know of some chart that compares them based on their features and priorities? Maybe something in the spirit of https://mobile.twitter.com/nixcraft/status/73938379662612889... but with more areas of comparison and less trying to be funny?
Rust: Wants to replace C++ as an expressive systems programming language. Syntax derived from C++. Emphasis on const correctness. Makes use of some functional programming concepts. Extensive metaprogramming. No garbage collection by default. Interface based polymorphism. The type system tracks memory ownership helping to prevent some classes of error at the cost of more cognitive overhead. The standard library is also written in a way that makes it hard to break things. The only one of the three that can easily be used to write libraries that can be called from other programming languages. Medium complexity to learn.
Nim: Slightly higher level than Rust. Reference counting garbage collection which can be turned off, but heaps are by default local to threads. Syntax derived from python. Emphasis on const correctness. Extensive compile time evaluation facilities. Object oriented polymorphism (for now). Sadly allows null by default for now. Extensive metaprogramming. Medium complexity to learn.
Go: Hightest level of the three. Traditional garbage collector. Interface based polymorphism. Simple and easy to pick up.
All three have good stories about multithreading. All three do their best to fix warts in C++ in things like declaration mirrors use syntax. All three start with the chainsaw turned off so you won't cut off your foot unless you're doing something genuinely dangerous like writing an OS or compiler.
For me, I'd use Rust for writing security critical or OS level things like kernels, system libraries, important utilities, and web browsers. Nim for small team applications where you can afford to be a bit clever and Go for large team projects where cleverness has to be discouraged.
I'm not a huge expert in any of these so there's probably important things I'm overlooking.
On that spectrum, I'd put D between your definition of Rust and Nim. Currently it does use a GC by default, but you can easily work above it when needed. Soon(tm) you will be able to specify what kind of GC to use (eg. provide your own) and the stdlib will adapt to it.
Just because the garbage collector is optional and the slightly higher emphasis on performance. Also the way it compiles to C. I have using Nim to program a microcontroller on my todo list but I'm not sure how I'd go about doing that in Go. It's weird though because Nim is certainly more expressive than Go is and usually that goes with being higher level.
For example, You can drop into c types using e.g. cstring and cint. Turn off or direct the gc. Manage memory for individual vars using the {.untracked.} pragma, c_malloc and c_free; easy integration of c libraries for obvious reasons; get pointers to things if you need them with ptr.
Have a look at some of these in the manual. Gc stuff is in the standard library somewhere.
I was drawn to it because it is high level, expressive and safe, but you can turn all this off when you need to and keep those bits contained. I'm using it with opencl.
Can't really comment on rust and have limited exposure to go.
It should probably also be worth mentioning that while the syntax is reminiscent of Python, much of Nim's semantics are derived from Modula-3. If you're familiar with Pascal-like languages, you'll find yourself right at home with Nim.
(and, on a side note, Go has a little Wirth in it too: it was concepted as "C meets Oberon", but what it borrowed from Oberon was its simplicity, and it hasn't kept nearly as many Wirthian quirks as Nim)
You put both Rust and Nim at 'Medium complexity to learn' but given that by default Rust has the 'borrow/lifetime checker' and that Nim has the GC, I'd say that Nim is easier to learn/use.
Of course you pay the price in performance (GC latency), even if Nim's GC is described as 'soft real time' I doubt that it would work well for a >60fps game and now with VR if the framerate drop you can make the user dizzy..
I've been leaning on Go lately because it has a large module community already. Nim, D, Rust are all on my radar to use once library maturity happens. For example, I need solid AWS, Azure, GEngine SDK support.
You've got a couple of really good answers, but there's another really important dimension: popularity. Choosing a popular language allows you to work with others, to hire people, to pass your project on, to allow your github repos to get popular, et cetera.
For that reason, I don't believe that Nim & D offer enough advantages and differences over Rust & Go that it outweighs their lack of popularity and hipness.
Of course others will say the same thing about Rust & Go: C, C++ and Java are much more popular and do currently fill basically the same niches as Rust & Go. You have to draw the line somewhere. It just happens that my line is drawn above Nim & D, but below Rust & Go.
Nim & D look like really awesome languages, though. They're just one killer project away from being popular, the way that Rails made Ruby popular. I would not be particularly upset if the situation reversed, if Nim & D got popular while Rust & Go got unpopular.
I was just skimming the post and found the redefining of 'using' very surprising. The old 'using' was for callsite reusability and the new one is for declaration. Optimizing for declaration site (which would be so few comparatively) doesn't make sense to me and also for declaration I want full type name and such.
I'm using Rust at work because it proved a bit more well suited for our purposes than Nim. However, it's still exciting to see steady progress on Nim; it has some really great and innovative language ideas and I hope its increasing polarity will see those features come to other languages too.
57 comments
[ 9.4 ms ] story [ 203 ms ] threadWe've got two internal tools that are written entirely in Nim, and it's been brilliant pretty much all the way through. The rough edges of previous versions are steadily sanded away, and our code becomes more expressive with each version. The biggest thing I'm looking forward to (once v1.0 rolls round) is having the "not nil" specifier be the default for all types. That's going to bring it in line with the other static typing checker we use regularly (Flow) which will be a boon to those of us (mainly me) that live in both worlds most days heh.
When using stuff like JS, the possible nulls are a bigger problem than a wrong type in general (still a problem, but IMO not as significant) still systems like TypeScript started without it.
- https://hookrace.net/blog/what-makes-nim-practical/#debuggin...
- https://hookrace.net/blog/writing-an-async-logger-in-nim/#op...
Edit: You can of course also change the program itself, using echo and writeStackTrace to figure out what's going on.
https://en.wikipedia.org/wiki/Compiler "A compiler is a computer program (or a set of programs) that transforms source code written in a programming language (the source language) into another computer language (the target language), with the latter often having a binary form known as object code."
For example, at the beginning of each function call, you insert a function call that pushes a new stack frame into some global stack, and store the function's arguments. Then, just before every return from the function, you pop the stack frame. When the program crashes, you write the stack to a JSON file, and use a language-specific debugger to view it.
[1] http://ftp.gnu.org/old-gnu/Manuals/gdb/html_chapter/gdb_11.h...
To be honest, I never managed to get familiar with many debuggers in a fashion that I could use them productively, except for Microsoft's Visual Studio tools (VC++, good ol' VB6 :-)). I know enough GDB to survive, and from what I've seen Nim works there almost just as well as plain C code.
There was a special debugger for Nim that worked by inserting instrumentation code during compilation, but that seems to have been deprecated.
still open :-(
(I add this not as a refutation, but merely because I found it amusing.)
Rust: Wants to replace C++ as an expressive systems programming language. Syntax derived from C++. Emphasis on const correctness. Makes use of some functional programming concepts. Extensive metaprogramming. No garbage collection by default. Interface based polymorphism. The type system tracks memory ownership helping to prevent some classes of error at the cost of more cognitive overhead. The standard library is also written in a way that makes it hard to break things. The only one of the three that can easily be used to write libraries that can be called from other programming languages. Medium complexity to learn.
Nim: Slightly higher level than Rust. Reference counting garbage collection which can be turned off, but heaps are by default local to threads. Syntax derived from python. Emphasis on const correctness. Extensive compile time evaluation facilities. Object oriented polymorphism (for now). Sadly allows null by default for now. Extensive metaprogramming. Medium complexity to learn.
Go: Hightest level of the three. Traditional garbage collector. Interface based polymorphism. Simple and easy to pick up.
All three have good stories about multithreading. All three do their best to fix warts in C++ in things like declaration mirrors use syntax. All three start with the chainsaw turned off so you won't cut off your foot unless you're doing something genuinely dangerous like writing an OS or compiler.
For me, I'd use Rust for writing security critical or OS level things like kernels, system libraries, important utilities, and web browsers. Nim for small team applications where you can afford to be a bit clever and Go for large team projects where cleverness has to be discouraged.
I'm not a huge expert in any of these so there's probably important things I'm overlooking.
D somewhat suffers from trying to do everything at once. There are lots of discussions.
Yes, I think this is what's driving my gut feel. Go feels quite ... hammer-y. Explicit iterators, very few "niceties", etc.
Have a look at some of these in the manual. Gc stuff is in the standard library somewhere.
This is an example I used recently: http://forum.nim-lang.org/t/567
Don't think it counts as low level but templates and macros are also pretty powerful if you need them. http://hookrace.net/blog/introduction-to-metaprogramming-in-...
I was drawn to it because it is high level, expressive and safe, but you can turn all this off when you need to and keep those bits contained. I'm using it with opencl.
Can't really comment on rust and have limited exposure to go.
(and, on a side note, Go has a little Wirth in it too: it was concepted as "C meets Oberon", but what it borrowed from Oberon was its simplicity, and it hasn't kept nearly as many Wirthian quirks as Nim)
For that reason, I don't believe that Nim & D offer enough advantages and differences over Rust & Go that it outweighs their lack of popularity and hipness.
Of course others will say the same thing about Rust & Go: C, C++ and Java are much more popular and do currently fill basically the same niches as Rust & Go. You have to draw the line somewhere. It just happens that my line is drawn above Nim & D, but below Rust & Go.
Nim & D look like really awesome languages, though. They're just one killer project away from being popular, the way that Rails made Ruby popular. I would not be particularly upset if the situation reversed, if Nim & D got popular while Rust & Go got unpopular.
Am I missing something here?