
What is special about Nim? - def-
http://hookrace.net/blog/what-is-special-about-nim/
======
benhoyt
Great write-up! I expected this to reference a few "normal" language features
like static typing, operator overloading, or generics, but instead it was a
list of some really neat off-the-beaten-track features:

    
    
      * Run regular code at compile time
      * Extend the language (AST templates and macros);
        this can be used to add a form of list comprehensions to the language!
      * Add your own optimizations to the compiler!
      * Bind (easily) to your favorite C functions and libraries
      * Control when and for how long the garbage collector runs
      * Type safe sets and arrays of enums; this was cool:
        "Internally the set works as an efficient bitvector."
      * Unified Call Syntax, so mystr.len() is equivalent to len(mystr)
      * Good performance -- not placing too much emphasis on this,
        but it's faster than C++ in his benchmark
      * Compile to JavaScript

~~~
rogerbinns
As a pythonista one thing that struck me in the code fragments is zeroes and
ones appearing everywhere. It looks very easy to have off by one errors. (It
is _very_ rare to have off by one errors in Python due to the way counting and
ranges work.)

~~~
def-
I guess you could use fewer magic numbers if you want, for example instead of:

    
    
      proc createCRCTable(): array[256, CRC32] =
        for i in 0..255:
    

You can write:

    
    
      proc createCRCTable(): array[256, CRC32] =
        for i in result.low .. result.high:
    

Or:

    
    
      proc createCRCTable(): array[256, CRC32] =
        for i, v in result: # index, value
    

Or define your own indices iterator:

    
    
      iterator indices(x) =
        for i in x.low .. x.high:
          yield i
    
      proc createCRCTable(): array[256, CRC32] =
        for i in result.indices:
    

I think I should propose adding indices to the standard library.

~~~
rogerbinns
It isn't magic numbers as such, rather the smattering of sometimes zeroes and
sometimes ones. If it was always zero or one it would be a lot less likely to
have off by one errors.

Python solves this by always starting from zero, and crucially not including
the final number - ie range(0,3) gives 0, 1, 2 (no 3). You can also do
negative indexing to count from the end - eg range(0, 3)[-1] gives the last
element (2). The right thing happens when you mix the length of things into
the arithmetic too - eg range(0, len(item)).

~~~
vbit
The 0s and 1s are specific to the examples. A range in nim `x..y` includes
both x and y. Sequences are always 0-indexed. Now, if you want to start with 1
for any range you can.

------
danso
A little OT: Courtesy of the Reddit discussion of the OP, a reference to the
discussion on Wikipedia about Nim, or rather, the discussion to delete its
Wikipedia entry:

[https://en.wikipedia.org/wiki/Wikipedia:Articles_for_deletio...](https://en.wikipedia.org/wiki/Wikipedia:Articles_for_deletion/Nimrod_\(programming_language\)_\(2nd_nomination\))

At what point does a language become noteworthy enough for a site that
contains full entries for side characters in non-canonical Star Wars novels?

~~~
captainmuon
Honestly, I thing a dozen Nim users should band together and register at
Wikipedia to turn the vote the next time someone tries to delete the article.
If the deletionists come with formalistic arguments, just synthesize a few
articles on sites that fulfill their WP:RELIABLE criteria. There's got to be
somebody working for a commercial (read: non-blog) website who doesn't like
deletionism and would post a small article on Nim (or any other topic
suffering from the same problem) just to stick it to them.

~~~
DanBC
Wikipedia is, for some things, severely broken.

Your post _will_ be seen by some wikipedians as a violation of some policy or
other. (Off the top of my head there's sock puppeting
[http://en.wikipedia.org/wiki/Wikipedia:Sock_puppetry](http://en.wikipedia.org/wiki/Wikipedia:Sock_puppetry)
"Do not ask your friends to create accounts to support you.")

~~~
captainmuon
But there is a difference between straight up sockpuppetry, and telling people
"If you like Wikipedia but are unsatisfied with the way it currently works,
then register and start contributing. If policy discussions or delete votes
come up, vote the way you believe you should (namely in this case
inclusionist)".

Its a bit like encouraging people to go to elections to raise the voter
turnout, to reduce influence of extremist parties. (Not that I'm comparing WP
editors with extremists, its just that I believe in both cases there is a
silent majority that risks being misrepresented!)

~~~
DanBC
I know that and you know that.

There are a considerable number of wikipedia admins who don't see it that way.
There are even more young wikipedians who don't yet have adminship who take a
hardline on that kind of thing - although to be fair WP has worked hard to
reduce that particular malign influence. (Removal of "vandal patrol"; stricter
oversight of twinkle and rollback use; etc etc).

------
rgacote
Thanks for the great write-up. In addition to straight-up language features,
what draws me to play with Nim is the full environment that has already been
built up including module packaging and debugger (particular pain points when
moving from Python to Golang).

Additionally, having compiled executables solves a Python pain point. I love
Python, but distributing packaged executables is an ongoing pain point.

------
BuckRogers
I've had my eye on Nim(rod) for a long time. I think this language may be the
right thing, at the right place at the right time.

I haven't seen a better boat for Python refugees to jump into. It's certainly
worth evaluating if moving from a Python2 codebase, rather than porting to 3.
It's far enough along that it can start poaching users looking for the best
place to jump off from 2.x.

The only thing I'd like to see them somehow do, is add a CPython2.x library
compatibility layer. If that could somehow be engineered into Nim before 1.0..
I think I'd declare Python3 to be in serious trouble.

The users WILL come if that's done. Maybe take a look at Nuitka in how to make
this possible with the binaries that Nim produces. Or even just include the
CPython2 runtime in the compiled binary if a user includes Python(2) code.

------
crazychrome
Nim is great, and this article is great, except until now no article about nim
managed to sell it to me like a simple Golang example including channel and go
routine.

Could any Nim advocate demonstrate a simple program that:

less than 50 loc

shows the greatest strength (1 killing selling point is enough)

~~~
klibertp
There's no such thing as a single "selling point" for Nim. Or rather there are
many such points: depending on what programming you do you'll appreciate
different language features. Making a list of many (not all of course)
powerful language features is - I think - the right approach to the problem
here.

It would probably be better if you explained what kind of problems you're
dealing with in your work: we could then look at Nim features and tell you if
there's something that would make your life easier and your work more
enjoyable.

~~~
crazychrome
I understand you (maybe including other Nim guys) feels undervalued/offended
when I asked for a sales pitch. Nim is an opensource project and probably
nobody makes a cent out of it, yet some arrogant guy like me treat the
priceless work like something off shelf in the supermarket.

sadly the reality is not everybody has the time to appreciate the beauty of
Nim unless he/she is convinced Nim identifies a problem largely ignored by
others and solves it beautifully. my point is, could you convince me?

------
mej10
This was a helpful writeup. Nim has a lot of really nice features. Are there
any problems or things you find lacking?

~~~
tenfingers
The idea that thisFunction and this_function are the same might be worse than
the problem they're trying to solve. I cannot unfortunately have experience
with larg-ish codebases in nim to tell if this would result in an actual
problem or not, but the idea that I have to scan between two possible
identifiers in the code can be a source of stupid bugs in the same vein as
case-insensitive identifiers.

On the other hand I can definitely see the appeal of it (some python packages
go against the recommendation and sort-of taint the style of other sources).

This so far was the only "weird" comment I could think of.

~~~
gjm11
That seems like a really bad idea. It means that searching for an identifier
requires you to allow for the possibility that there might be any number of
underscores inserted anywhere. I suppose in practice you'll rely on the fact
that no one will be inserting them other than at word boundaries, but it still
seems horrible.

(I'd worry about ambiguities of the experts exchange / expert sex change type,
too, but my guess is that they're extremely rare and usually either harmless
or instantly caught by the compiler. Still, the mere possibility makes me
twitchy.)

~~~
ebiester
Certainly, I would have some sort of lint to enforce naming conventions. I
don't like it at all. Searching for a function becomes a nightmare.

~~~
EXetoC
Is it not good enough to have specific grep tools? nimgrep for example, and
there are procs for working with this IIRC.

~~~
def-
I prefer to have a consistent code base, then I can use the internal tools of
my editor, which are not aware of Nim's identifier rules.

------
tim333
Nice article.

I was going through trying to follow the instructions and hit a couple of
issues:

-For "You should then add ~/.nimble/bin to your $PATH" it took me quite a while to figure I had to enter "ln -s ~/.nimble/bin/nimble /usr/local/bin/" in my Mac's terminal to do that. I guess experienced devs know that stuff but beginner here.

-There's a bug in the client.nim and server.js code where the client refers to element "foo" but the server refers to element "item". Changing them both to foo got it to work.

Nim seems kinda cool.

~~~
def-
> -For "You should then add ~/.nimble/bin to your $PATH" it took me quite a
> while to figure I had to enter "ln -s ~/.nimble/bin/nimble /usr/local/bin/"
> in my Mac's terminal to do that. I guess experienced devs know that stuff
> but beginner here.

Actually you should add "export PATH=$PATH:$HOME/.nimble/bin/" in ~/.profile,
~/.bashrc, ~/.zshrc or whatever your shell requires.

> -There's a bug in the client.nim and server.js code where the client refers
> to element "foo" but the server refers to element "item". Changing them both
> to foo got it to work.

Thanks, fixed.

------
detrino
FWIW, I did a more direct translation[1] of the Nim code into C++. The current
C++ code does things like memcpy a std::bitset on every recursive call. I also
wanted the code to be doing the exact same thing as Nim is (vector with 1 byte
per bool, globals for data, and I left everything as int when I would normally
use other types).

The result is that C++ now just barely outperforms Nim: 1074ms for C++ vs
1165ms for Nim.

[1] [http://ideone.com/q838cJ](http://ideone.com/q838cJ)

------
tux3
>Yes, that's right: All we had to do was replace the var with a const.
Beautiful, isn't it? We can write the exact same code and have it run at
runtime and compile time. No template metaprogramming necessary.

Worth pointing out is that modern C++ does this too. Just add a constexpr, no
metaprogramming necessary. Modern C++ really does feel like a new language.

------
rurban
Special about Nim is also that Wikipedia consistently tried to delete the
article about Nimrod (and did), because someone considered it not noteworthy.
What a joke those editors are. If you have no idea about software languages
don't interfere.

------
xixixao
I haven't noticed this, Nim is the new name for Nimrod.

~~~
inglor
Relevant HN thread:
[https://news.ycombinator.com/item?id=8351773](https://news.ycombinator.com/item?id=8351773)

~~~
def-
And the first release with the new name was just a few days ago:
[https://news.ycombinator.com/item?id=8809215](https://news.ycombinator.com/item?id=8809215)

------
thomasfoster96
I'm not sure I like Unified Call Syntax. I think myvar.len() should be
different to len(myvar), even if they end up returning the same value. Then
again, I'm probably missing some key reason why it's useful.

Adding my own optimizations to the compiler sound useful enough. I might see
if I can implement this in the language I'm making.

------
halayli
I copy/pasted the code in the article and compiled each one. I am getting very
different ratios compared to the ones you posted:

tmp$cc -Wall -O2 test.c -o test && time ./test

real 0m1.041s user 0m0.998s sys 0m0.029s

nim-0.10.2$./bin/nim --opt:speed c test.nim && time ./test

real 0m1.943s user 0m1.894s sys 0m0.036s

~~~
dom96
Try compiling with -d:release instead of --opt:speed.

------
barbudorojo
What I don't like about Nim is that there is not a repl. In Lisp and Clojure
you don't need to compile things.

Could someone give a brief comparison between Clojure and Nim? Let's suppose
that we implement Clojure in Nim is this a crazy idea?, What about
implementing Shen in Nim?. Many people complain because sbcl is not easy to
use with C++ libraries, could an implementation in Nim amilliorate those
problems?. Many more questions arise but those mentioned are enough.

~~~
def-
Well, there is a REPL, but it's not that great:

    
    
        $ nim i
        >>> for i in 0..10:
        ...   echo "Hello World"[0..i]
        ...
        H
        He
        Hel
        Hell
        Hello
        Hello 
        Hello W
        Hello Wo
        Hello Wor
        Hello Worl
        Hello World
    

To use up/down keys, build the Nim compiler with "./koch boot -d:release
-d:useGnuReadline" or run "rlwrap nim i" instead.

Edit: It's even buggier than I remembered, best avoid it and use "nim -r c
file" instead.

~~~
hugs
What bugs or things-that-are-not-great have you run into with Nim's REPL?

~~~
barbudorojo
It seems that you can't use any libraries. After using import it doesn't work
anymore.

------
StrykerKKD
Nice article, although I couldn't really understand some of the examples which
had template in it.

~~~
RaecKK
Agreed. When the manual says you can pattern match with term rewriting macros,
I think of Erlang pattern matching. Would something like this be possible?

    
    
        template mysum{a = @[]}(a: seq[int]): int = 0
        template mysum{a}(a: seq[int]): int =
          while a.low <= a.high:
            a[a.low] + mysum(a[a.low + 1 .. a.high])
    
        var x: seq[int] = @[1, 2, 3]
    
        echo mysum(x)

~~~
def-
Term rewriting templates are only supposed to be optimizations, not change the
semantics. They happen on the AST, so the pattern matches are on the AST as
well. You won't get the actual values of any variables, they aren't even known
at compile-time anyway.

