
What makes Nim practical? - def-
http://hookrace.net/blog/what-makes-nim-practical/
======
BoppreH
I read the Nim manual a while ago ([http://nim-
lang.org/manual.html](http://nim-lang.org/manual.html)), back when it was
Nimrod.

As a Python user, I loved it. Every single problem I had with Python, Nim
seemed to have solved elegantly. Performance, distribution, typing...
Everything looked perfect, and none of the Python expressiveness seemed to
have been sacrificed.

But it was transpiled to C, and the abstraction was leaky. Every once in a
while the manual would mention that certain structures were not supported, and
it was clear C was the culprit. I think the most glaring example were nested
functions, or something similar.

I thought to myself "this will bite me in the ass sooner or later" and gave
up. Maybe it's time to try again. If they plugged the abstraction holes, this
will be a killer language, with applications everywhere.

~~~
adrusi
Nim isn't compiled to C in the same way that, say, Coffeescript is compiled to
Javascript.

Nim's compiler converts the AST into an intermediate representation that can
be compiled to several backend. The primary backend is C source code, but it
also supports outputting Javascript (experimentally) or interpreting the
intermediate representation ala Python.

The difficulty of developing the IR -> C transformation certainly influences
the features of the language, and certain features, like tail calls, can't be
implemented because Nim expresses functions as C functions for the benefit of
foreign code. I wouldn't say it's a leaky abstraction though, not any more
than C is a leaky abstraction over machine code.

~~~
dogprez
Your example isn't exactly true. Clang and GCC both do tail call
optimizations. Compiling language functions to C functions doesn't 100%
preclude you from TCO. [http://david.wragg.org/blog/2014/02/c-tail-
calls-1.html](http://david.wragg.org/blog/2014/02/c-tail-calls-1.html)

~~~
bch
See also:
[http://www.pipeline.com/~hbaker1/CheneyMTA.html](http://www.pipeline.com/~hbaker1/CheneyMTA.html)

It looks like work/research in this area has been going on for at least ~20
years.

~~~
jpolitz
Indeed it has. For a few more examples, see also
[http://www.ustream.tv/recorded/43777177](http://www.ustream.tv/recorded/43777177),
and
[http://www.ccs.neu.edu/racket/pubs/stackhack4.html](http://www.ccs.neu.edu/racket/pubs/stackhack4.html).
Pyret ([http://pyret.org](http://pyret.org)) uses similar stack techniques to
these to simulate an arbitrarily deep stack while compiling to JS.

------
JimmyM
Great post. I thought I'd comment just to say about the relative URL ../what-
is-special-about-nim not working as intended from the homepage and the link to
[http://nim-lang/](http://nim-lang/) which should presumably be [http://nim-
lang.org](http://nim-lang.org)

Seems a shame to make such a pedantic and insubstantial comment on such an
interesting article about a language I'd not come across, but thought the
author might like to know.

~~~
def-
Oops, I thought I checked all links. Thank you!

------
jwiley
Can someone point me to an explanation of "Nim is the only language that
leverages automated proof technology to perform a disjoint check for your
parallel code"? This is mentioned prominently on the main page...but scanning
the docs, the FAQ, Dr. Dobbs, and Googling 'nim disjoint' didnt lead me to a
detailed explanation.

~~~
Araq
Disclaimer: I'm the lead designer of Nim.

pcwalton's remark is excellent but "automated proof technology" is not a well
defined term. What I mean by this is that it goes beyond what a traditional
type checker can do. I don't think Rust can do exactly the same things via its
borrow checking and its iterators, but I might be wrong. Note that the very
same analysis also proves your index bounds are correct.

Nim's disjoint checker is so experimental that its docs are indeed very terse
and we only have a couple of test cases for now. That said, the disjoint
checking is restricted to the 'parallel' statement, so its complexity only
affects this language construct and not the whole language. You can think of
it as a macro that does additional checking.

~~~
dbaupp
_> I don't think Rust can do exactly the same things via its borrow checking
and its iterators, but I might be wrong_

Reading [http://nim-lang.org/manual.html#parallel-statement](http://nim-
lang.org/manual.html#parallel-statement) point by point (disclaimer, I think
Nim is very cool, but safe parallelism is one of Rust's strongest points):

 _> Every location of the form a[i] and a[i..j] and dest where dest is part of
the pattern dest = spawn f(...) has to be provably disjoint. This is called
the disjoint check._

The type system guarantees disjointness when necessary: a mutable reference
`&mut` is guaranteed to be the only way to access the data it points to at any
given point in time and iterators over mutable references preserve this
guarantee, so disjointness-for-writing is automatic.

 _> Every other complex location loc that is used in a spawned proc (spawn
f(loc)) has to be immutable for the duration of the parallel section. This is
called the immutability check. Currently it is not specified what exactly
"complex location" means. We need to make this an optimization!_

Rust generalises immutable to "safe to be used in parallel"; everything that
is (truly) immutable satisfies this, but so do, for example, memory locations
that can only be used with atomic CPU instructions, or values that are
protected by a mutex. There's no way to get data races with such things, so
they're safe to refer to in multiple threads.

This is captured by the Sync trait (types which can be used from multiple
threads in a shared way implement it): [http://doc.rust-
lang.org/nightly/std/marker/trait.Sync.html](http://doc.rust-
lang.org/nightly/std/marker/trait.Sync.html)

 _> Every array access has to be provably within bounds. This is called the
bounds check._

Rust's iterators give in-bounds automatically, but there's also no restriction
about requiring bounds checks or not. (What does this rule offer Nim?)

 _> Slices are optimized so that no copy is performed. This optimization is
not yet performed for ordinary slices outside of a parallel section. Slices
are also special in that they currently do not support negative indexes!_

I'm not sure what this means in the context of Nim, but passing around a Rust
references never does a copy (even into another thread).

(Disclaimer 2: it's not currently possible to pass a reference into another
thread safely, but the standard library is designed to support it, the only
missing piece is changing one piece of the type system,
[https://github.com/rust-lang/rfcs/pull/458](https://github.com/rust-
lang/rfcs/pull/458) , to be able to guarantee safety.)

------
moe
I love how these new languages compile into a static binary and thereby avoid
the deployment nightmares of Ruby/Python.

More of that please!

~~~
untitaker_
I came across
[pex]([https://github.com/pantsbuild/pex](https://github.com/pantsbuild/pex))
a while ago. It basically compiles your package and all its dependencies into
a single zipped module.

I never had the opportunity to try it out myself though.

~~~
woadwarrior01
If PEP-441[1] makes it to Python 3.5, pex like functionality will be a part of
the standard library.

[1]:
[https://www.python.org/dev/peps/pep-0441/](https://www.python.org/dev/peps/pep-0441/)

~~~
untitaker_
It's not quite the same I think. The format is very similar, yes, and I think
it'd be nice if the PEX _program_ could be made to work with this PEP.
However, the PEX program bundles dependencies, which this PEP doesn't seem to
be explicitly about.

------
iopq
I just realized something: Nim is like a faster Python or a better Go lang

It's not really competing in quite the same space as say, D or Rust. It's like
a statically typed scripting language.

~~~
xkarga00
Care elaborating on why is it a better Golang?

~~~
beeworker
Just about everything is better than Go. Nim, Rust, OCaml, Haskell... Did you
read the submission? And for further enlightenment, the link to the previous
post on the blog about what makes Nim special? Here's a link to a rant
comparing Go and Rust, which includes some links of its own highlighting
further issues with Go: [http://www.quora.com/How-do-Go-and-Rust-languages-
compare](http://www.quora.com/How-do-Go-and-Rust-languages-compare)

~~~
xkarga00
I've read both the submission and the articles that exist inside that Quora
link you posted and I am still not convinced. IMO what makes a language better
is end products and not features. When Rust becomes stable, its community will
produce great software but I don't think all of the rest languages you
mentioned have produced (or will do) better software than Docker, Kubernetes,
OpenShift, etcd, btcd, and a ton of other Go software.

~~~
gnuvince
> IMO what makes a language better is end products and not features.

It's useful to distinguish between "the language" and "the tool". Some
programming languages are terrible from a language design perspective (PHP,
JavaScript, MATLAB), but they still have great tools (IDEs, build tools,
package managers) and libraries to help programmers create good and
interesting software.

~~~
xkarga00
The tooling around Go is good but not that great. What makes Go better than
all those languages is that it's more complete: a language that does not get
into your feet, good tooling, great community, and more. IMHO saying that a
language is better or worse based only on "the language" is silly.

------
antman
I tried it and it is easy and fast. But the ecosystem is still not very large.
I think that it should support building libriaries directly accessible from
python including passing numpy arrays directly to nim. That would make a lot
of people to jump right in creating libraries and thus extending its own
ecosystem.

~~~
curiouslearn
Something like Julia's PyCall package that allows calling arbitrary Python
packages from Julia would also be great.

~~~
chrisheller
NimBorg is what you're looking for,
[https://github.com/micklat/NimBorg](https://github.com/micklat/NimBorg)

------
joelthelion
Just add autocompletion and syntax checking for the major editors and people
will start adopting it.

~~~
def-
That's on its way!

~~~
codexon
Doesn't nim already have autocomplete?

~~~
girvo
Built into the Nim compiler, yeah, it has a `idetools` feature that makes
integrating it into an IDE far simpler. I've been playing around lately with
getting it into Textadept, now that Textadept has a better "call some
particular binary and get input and output from it" story.

------
towelguy
I wonder if it can generate bindings for Python like Vala does[0]? That would
make it even more interesting for Python developers.

[0] [https://github.com/antono/vala-object](https://github.com/antono/vala-
object)

~~~
chrisheller
I haven't looked closely at the Vala stuff that you mentioned, but it is very
straightforward to generate shared libraries in Nim with exported functions
that you can access via ctypes. That's not quite the same as generating a
python module that you can directly import, but it gets the job done.

You might also be interested in NimBorg,
[https://github.com/micklat/NimBorg](https://github.com/micklat/NimBorg) ,
which supports embedding Python or Lua in a Nim program.

------
namuol
I perked up as soon as I read this:

    
    
        # Table created at compile time
        const crc32table = createCRCTable()

~~~
CyberShadow
This is not an unique feature today, you can do the same in D and Rust and
even C++14, I think.

~~~
namuol
"Hey Nim, 2014 called... they want their language features back."

I jest.

But seriously, D, Rust, and C++14 are about as familiar to me as Nim.

~~~
CyberShadow
To be fair, D has had it since 2007 :)

------
egeozcan
I keep coming back to it, and I really like it but wouldn't it be great if it
had interfaces? I really want to restrict the generic type but there seems to
be no way other than using templates[1].

[1]:
[https://github.com/Araq/Nim/blob/master/lib/pure/collections...](https://github.com/Araq/Nim/blob/master/lib/pure/collections/lists.nim#L109)

~~~
def-
User defined type classes can be used for this, but they're still
experimental: [http://nim-lang.org/manual.html#user-defined-type-
classes](http://nim-lang.org/manual.html#user-defined-type-classes)

~~~
egeozcan
I can't believe how I missed that. Maybe this is added recently? Anyway, thank
you very much!

------
Roboprog
Is there a "ctags / etags" utility for nim yet?

~~~
def-
That's something nim-idetools can do once it works properly: [http://nim-
lang.org/idetools.html](http://nim-lang.org/idetools.html)

------
honhon
I played around with Nim and it has huge potential. It is early days and I
would like to thank the creators of the language. A decent IDE is the only
issue for me. I tried all the IDE options and it was stark. The idetools
didn't work for me and the unit tests failed on Ubuntu 14.04.

At the moment small projects and libraries should be fine but the lack of IDE
would be an issue for bigger projects.

------
xtrumanx
> That means you end up with a single binary that depends solely on the
> standard C library, which we can take for granted on any operating system
> we're interested in.

What exactly does that mean? Does the end-user of my binaries require a C
compiler? Which operating systems are "we" interested in. I'm interested in
Windows and specifically Windows CE.

~~~
def-
That means if programs written in C work on your OS, so do the ones in Nim.

~~~
xtrumanx
Sorry if this is a silly question but I've always thought of C as generating
machine code and it had compilers available in any imaginable platform besides
perhaps really niche stuff.

Were my assumptions accurate?

~~~
geoelectric
Simplified, but yeah. It generates intermediate object code, which is
transformed to machine code.

And as you say, pretty much every platform in existence has a C compiler
targeting it. In many cases, you use what's a called a cross-compiler, which
lets you generate code for, say, Arduino using tools run on, say, Linux. But
one way or the other there'll be a way to compile for it.

Net result is that as long as the code isn't doing something that is specific
to the platform (memory layout assumptions, asm blocks, Windows API, etc.) the
same C code will run on many different platforms. You'll have to recompile it
for each one, but you won't have to change the source (much).

If I understand correctly, Nim ultimately generates C source (among other
options) which then goes through the above process. So it has the same level
of portability.

------
CyberShadow
Nim has some good ideas but I can't get over the syntax:

    
    
      - Significant whitespace, but tabs are forbidden
      - No block comments, save for `discard """ ... """`
      - Identifiers are case and underscore-insensitive (FOO_BAR === fooBar === fo_ob_ar)

~~~
mVChr
> \- Identifiers are case and underscore-insensitive (FOO_BAR === fooBar ===
> fo_ob_ar)

In the language design stages who in the world thought this would be a good
idea? Even PHP doesn't do that.

~~~
bpicolo
Let's be realistic. If you have somebody naming variables:

foo_bar = blah

foobar = blah

fooBar = blah

That's someone you really don't want to be coding anywhere near, because it
leads to really, really confusing code. So nim is just enforcing not being
able to do it it as a language.

~~~
nkurz
I agree, but the problem is that you don't ever want to do this whether those
are three different variables (or is that two?) or whether all are alternative
forms of the same case/underscore insensitive name. Nim is going out it's way
to make the syntax you have about legal (will all of these equivalent), which
strikes me as a bad move.

The best case for usability is that this "feature" never used, which makes it
an odd design choice. The worst case is that the feature is used frequently,
there is no clear language norm, visually scanning for variables is harder,
search and replace requires dedicated tools, and subtle bugs abound. Far
better (in my personal opinion) to make identifiers case sensitive and enforce
consistency with style guidelines and code "prettifiers".

The current Nim approach is being called cs:partial (case sensitive partial)
and makes the first letter case sensitive but all others insensitive. This
like an awkward compromise, and needlessly complicated. The best proposal I've
seen suggests making "_x" equivalant to "X" (underscore is an alias for "next
letter is capital"). But I don't see it as better than case insensitive plus
strong code conventions.

~~~
eatfish
I think it would be a lot more palettable if Nim enforced _one_ of those
coding conventions per module, while letting users of that module reference it
any way they liked. e.g. my team could exclusively use camelCase and the
compiler enforced that in our modules, while the same code could be handed off
to some other team that exclusively uses snake_case.

------
towelguy
> Nim libraries are statically compiled into our binary as well.

Does that mean one can not use GPL libraries in non-GPL programs? With other
languages you can get around that by linking dinamically.

~~~
pavlov
Actually that only applies to LGPL libraries -- pure GPL doesn't allow dynamic
linking, even. (That's the most common interpretation anyway, and the reason
why LGPL exists.)

------
malkia
I'm assuming "staticExec" is not sandboxed in any way...

It's one thing to make your compile stuck it's head while doing #include "aux"
in windows, but completely different to treat source code as "shell"-script.

(I see the point, and it's a great feature, but with too much power).

~~~
monono
Sure, just don't use it then.

