
A Quick Comparison of Nim vs. Rust - arthurtw
http://arthurtw.github.io/2015/01/12/quick-comparison-nim-vs-rust.html
======
andybak
It's feels like a shame to me that the one Python maxim that Nim has chosen to
reject is "there should be one and preferably only one way to do it" \- from
this flows so much of the other goodness of the Python ecosystem. I worry that
some of the metaprogramming magic that Nim allows will result in the loss of
that feeling that I can view source on almost any 3rd party Python code and
immediately feel like I can follow what's going on. Maybe community standards
can help restrain this somewhat.

Also:

> mapWidth, mapwidth and map_width all map to the same name

Why or why? Editors and IDEs now need Nim-aware search code!?

~~~
okasaki
On the other hand, it's quite convenient if you can't remember the exact name
and it saves you a look-up e.g. quick_sort vs quicksort vs quickSort - either
work

~~~
FeeTinesAMady
That means that all three forms will wind up in any Nim project that gets
large enough, though. Hardly a good thing.

~~~
jiggy2011
If they all work, does it even make a difference? Besides it would be trivial
to write a refactoring tool that can autoreplace all instances with the
preferred form.

~~~
duaneb
It has little benefit and requires new tooling to do simple refactoring like
"rename".

> Besides it would be trivial to write a refactoring tool that can autoreplace
> all instances with the preferred form.

This should be part of the language if it's being so lax with identifier
uniqueness. And if it's so trivial, you should write it so people can't
complain anymore.

~~~
dom96
I don't get why people get so worked up over this. It's not a "little" benefit
in my opinion. In regards to drawbacks I can only see one, and that is
grepping for the identifiers becomes more difficult.

~~~
duaneb
> It's not a "little" benefit in my opinion

Could you explain it, then? An identifier refers to a single thing. I don't
see having multiple ways to refer to that identifier as a win AT ALL—it may be
a win for people who are too lazy to learn their own code base, but it makes
code hard to read, hard to maintain, and hard to refactor.

Meanwhile, having an identifier unique makes it easy to index, easy to
manipulate.

~~~
dom96
I don't understand why you think it makes code hard to read. In what situation
would a code base use fooBar and foo_bar as two different identifiers meaning
two completely different things? The idea behind this "style insensitivity" is
that amyAtePizza has the same meaning as amy_ate_pizza. Why should it be
distinguished in a programming language?

~~~
duaneb
> In what situation would a code base use fooBar and foo_bar as two different
> identifiers meaning two completely different things?

You don't. It's a terrible idea to mix naming conventions.

> amyAtePizza has the same meaning as amy_ate_pizza.

WHY?! What possible benefit could it have? Why would you be mixing styles in
the first case? Why can't you just remember which style hopefully your entire
code base uses?

~~~
dom96
I wouldn't mix styles inside my own code base. But what if I am using somebody
else's library which uses a different style? The benefit is that I can then
use the style I have been using in my code base to call the functions in that
library without mixing naming conventions.

~~~
Dylan16807
I hope you never move code between different code bases, then.

Wouldn't it be a lot simpler to have a single style?

------
ot
> It’s mysterious that Rust’s release version with -i ran slightly faster,
> though.

That's actually not surprising: a large fraction of time is spent in the map
lookup, which in Rust is implemented as a B-tree, thus lookup time is (mildly)
dependent on the map size. If keys are lowercased before inserting them, the
map ends up having fewer elements.

The Nim version uses instead hash tables, whose lookup time is near-constant
(that is, excluding memory hierarchy effects).

~~~
AYBABTME
This seems an odd choice to me (default to B-Tree instead of hash map). I'd
expect a sorted map to be a special case, not a general one. Do you happen to
know the rationale?

Not criticizing, just curious.

~~~
euid
It's a poor choice on the author's part

[http://doc.rust-lang.org/std/collections/](http://doc.rust-
lang.org/std/collections/)

    
    
        Use a HashMap when:
        
        - You want to associate arbitrary keys with an arbitrary value.
        - You want a cache.
        - You want a map, with no extra functionality.
        
        Use a BTreeMap when:
        
        - You're interested in what the smallest or largest key-value pair is.
        - You want to find the largest or smallest key that is smaller or larger
          than something
        - You want to be able to get all of the entries in order on-demand.
        - You want a sorted map.

~~~
arthurtw
I chose it because I wanted to learn Rust by implementing my own BTreeMap
struct. I admit it’s not a good choice performance-wise, and made the
comparison with Nim less meaningful.

I’ve updated the code and article with HashMap. It runs about 6~7% faster than
BTreeMap.

------
skrebbel
I like how articles like this help elevate Nim's status. To me, deep inside,
Rust always felt like this grand high-stakes project, by wise people at this
big experienced company Mozilla, and Nim felt like a hobby project that got
out of hand. That's an entirely unfair judgment of course, but I bet more
people feel that way. I like that Nim is starting to get the attention it
deserves.

~~~
arthurtw
Yes, I think Nim deserves more attention, and that’s part of the reason I
wrote this article.

~~~
baldfat
Never even gave Nim a thought. Just read some and now I think I will try a
little pet project with it. Really looks very interesting. I am wondering how
the C, C++ , Objective C and JavaScript from one compiler works. personally I
never want to touch JavaScript but it might be interesting how this works.

------
pcwalton
The first benchmark is primarily a comparison of Nim's PEG package to Rust's
libregex package. The two have very different algorithms, and libregex is
optimized to avoid exponential blowup on pathological regexes. It's missing a
fallback to the backtracking algorithm at present.

Using rust-pcre would probably mitigate this problem.

~~~
burntsushi
I was still pretty surprised that `regex` was getting killed. It turns out, I
think, that `\w+` in Rust is Unicode friendly, but it's not in Nim. In cases
where most matches fail, checking the full spectrum of Unicode "word"
characters becomes pretty expensive (although it is at least doing a binary
search on contiguous ranges of characters: [https://github.com/rust-
lang/regex/blob/master/src/vm.rs#L23...](https://github.com/rust-
lang/regex/blob/master/src/vm.rs#L237-L238)). When I switched `\w+` to
`[a-zA-Z0-9_]+` in the Rust program, I saw a ~60% performance increase.

> and libregex is optimized to avoid exponential blowup on pathological
> regexes. It's missing a fallback to the backtracking algorithm at present.

Maybe. RE2/C++ doesn't do any backtracking AFAIK, but it appears near the top
of any benchmark I think.

~~~
arthurtw
Bingo. With `regex!(r"[a-zA-Z0-9_]+")`, Rust finally runs faster than Nim.
I’ve updated the article.

------
gfasdgsfd
I'd guess that pulling that try-catch out of the loop would make things go
much faster. Nim doesn't use 0-overhead exceptions, so setjmp needs to be
called each time the try-catch is entered.

You should also use the re module, PEGs is not nearly as optimized as PCRE.

~~~
arthurtw
I’ll try that later, though the Nim version is fast enough after using
-d:release flag.

------
egeozcan
I like Nim. I used it for a few side-projects as well. The only thing it
definitely needs before feeling really solid is trait (interface, contracts or
whatever you call it) support IMHO. Current alternative is "compiler does
copy-paste for you", aka templates. See:
[https://github.com/Araq/Nim/blob/master/lib/pure/collections...](https://github.com/Araq/Nim/blob/master/lib/pure/collections/lists.nim#L109)

------
_pmf_
From what I have read, Nim has a much better cross-compilation story (i.e. it
delegates to the available C cross-compilation toolchain instead of requiring
the Nim compiler and toolchain to be compiled for the cross target).

Rust, as I understand, requires the Rust compiler to be compiled for the
cross-target; is this correct?

~~~
dbaupp
The compiler does not need to be compiled for the cross-target to just run
binaries, just the standard library like C; but, once they exist, running the
compiler directly with `rustc --target=...` and using the dependency/build
manager cargo `cargo build --target=...` both work fine.

Of course, it is harder to obtain cross-compiled versions of the Rust standard
library at the moment, so what you say is likely true.

------
dom96
Are you just using --opt:speed to compile the Nim examples? For maximum
performance you should be using -d:release.

~~~
mrob
-d:release disables bounds checking, so the Rust examples would have to be modified for unchecked indexing for a fair comparison.

~~~
dom96
It disables a lot of other things too. The current comparison is unfair. Why
do the examples need to be modified to disable bounds checking for Rust? If
it's easier you can compile the Nim examples with -d:release and enable bounds
checking by also supplying --boundChecks:on.

~~~
arthurtw
I’ve added additional results with Nim’s --boundChecks:on flag. Thank you two
for the suggestions.

------
TylerE
I'm starting to really wish there was a GC-free (or at least) GC optional
version of Nim. Nim with Rust's memory semantics would just be the best of
everything.

~~~
vbit
I believe you can turn off the GC for Nim. Then you're just limited to
libraries that don't rely on the GC, and fully manual memory management.

~~~
steventhedev
This is more of an option than you might think. Nim plugs in to C libraries
much easier than you would expect from an FFI. That means even if the stdlib
depends on the GC heavily, you can eschew it for the C stdlib.

For example:

    
    
        proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
    

I'd be interested in seeing a comparison of higher level language features
rather than performance (which is generally a result of data structure
choices, etc). Stuff like package managers, concurrency primitives, cross
compiler support, memory management, and general syntax.

~~~
skrebbel
Wow, that's a pretty cool insight. Basically that means you could use "Nim
without GC" as "a better C". I can see very few downsides. You could probably
start using it in existing C projects much like you could start adding .scala
files to an existing Java project.

~~~
girvo
As an example, that's exactly what I'm doing with my SDL game experiments; I'm
using Nim as a "better C", effectively. It works rather brilliantly.

------
hamstergene
Why don't you run GC_fullCollect() at the end of Nim programs? You may
unknowingly be comparing a program which actively runs destructors and frees
memory with one that basically leaks everything (because GC does not happen to
be triggered).

------
joelthelion
One thing they both lack that hinders wider adoption : good IDE support. For
me YouCompleteMe support is the only thing preventing me from switching for my
side projects.

~~~
MrBra
How can you base the choice of a language solely on that?

~~~
dagw
I wouldn't chose a language based solely on that, but when faced with a few
equally good choice, then I will absolutely go with the one that has a, to me,
better development environment.

------
nim_user
Nim needs to move it's discussions to a mailing list if the authors want to
gain more serious developers onboard.

Polling a poorly implemented web forum speaks leaps and bounds about the kind
of attitude you need to have to discuss, develop or debug issues around the
Nim toolchain.

This is something that Nim developers can instantly do to boost the
attractiveness of the language.

Please, do this.

~~~
ilaksh
The web forum is better than 90% of the forums out there. It is very fast,
looks great, has syntax highlighting and a fast search. How could you possibly
think that a mailing list is better? What is this, 1981? I hate mailing lists.
The github issues is where a lot of serious discussion goes on and if you give
github your email and contribute or subscribe you can get spammed with every
single issue discussion like me. Anyway I think the highest bandwidth most
advanced option is sometimes IRC which of course Nim has too.

------
fiatjaf
Here's a pure code comparison of Nim vs Rust:
[http://rosetta.alhur.es/compare/nimrod/rust/](http://rosetta.alhur.es/compare/nimrod/rust/)

~~~
heinrich5991
That's partially outdated for Rust, but I guess Rust is too much of a moving
target.

For example `from_str::<int>` should be `.parse()` today.

~~~
fiatjaf
The code samples are from the RosettaCode[1]. They are probably lacking a
frequent contributor for making and fixing Rust code examples.

[1]:
[http://rosettacode.org/wiki/Rosetta_Code](http://rosettacode.org/wiki/Rosetta_Code)

~~~
steveklabnik
There's a repository where Rust versions are being worked on:
[https://github.com/Hoverbear/rust-rosetta](https://github.com/Hoverbear/rust-
rosetta)

------
rjammala
Can you benchmark this C++ code on your system for comparison?
[https://github.com/rjammala/C/blob/master/perf.cpp](https://github.com/rjammala/C/blob/master/perf.cpp)

I did not add the case sensitiveness option to it.

------
lmm
It'd be good to see how these new languages compare to established ones that
offer similar features - maybe OCaml and Haskell.

------
errordeveloper
I really wouldn't consider it reasonable comparison, when one language has a
sufficient compiler that is written in itself for most part, and the other
still only compiles to C.

~~~
ziotom78
Why should such comparison be unreasonable? The fact that a compiler
internally produces C/Assembly/Brainfuck/whatever code to produce the final
binary should be relevant only for computer science theorists, not for the
majority of the users out there (like me).

Also, I find one of your statements quite contradictory: by saying that Rust's
compiler "is written in itself", you seem to imply that Nim is not. But this
is not true: Nim's compiler is almost 100% pure Nim.

(Last but not least: to me it seems not true that Nim "only compiles to C", as
it provides multiple backends. See here: [http://nim-
lang.org/backends.html](http://nim-lang.org/backends.html) .)

~~~
errordeveloper
Perhaps I have had a wrong impression since I read on Nim quite a while ago
last time and should checkout this article now. Thatnks for pointing this out!

