

Nimrod for C programmers - stesch
https://github.com/Araq/Nimrod/wiki/Nimrod-for-C-programmers

======
eliteraspberrie
I strongly disagree with the rationale for not supporting unsigned integer
types by default. In fact, I think unsigned should be the default, and the
advice on the Escher Technologies blog is harmful.

Other than that, Nimrod has been a pleasure to use. If you need a
metaprogramming language to generate C, use Nimrod.

~~~
barrkel
I'll assert that a majority of C programmers do not understand unsigned types
and misuse them.

It's quite common to end up needing to use both signed and unsigned types in
the same expression and to end up invoking undefined behaviour trying to
protect yourself. C overflow semantics (i.e. undefined) in particular.

Signed types should be the default, and overflow should be defined as wrapping
two's complement. There's very good reasons why C# and Java chose these
defaults.

The places where unsigned numbers are justified are incredibly rare: bitwise
operations, and working with >2GB heap sizes on 32-bit machines. That's about
it. In almost every other circumstance, using a signed type (the next size up
if the range is inadequate) is better.

Especially pernicious is using something like size_t for things like container
entry counts. It's very common to add and subtract with container counts, and
very easy to end up inadvertently wrapping or mixing with signed types in
common container algorithms.

PS: my experience was deeply coloured while working on the Delphi RTL, making
it overflow safe. It was not trivial.

PPS: it was revealing that the comments on the article arguing in favour of
unsigned types repeatedly made programming errors and invoked undefined
behaviour. That's because unsigned types are misunderstood and misused.

~~~
Nursie
Third case, dealing with raw data from networks, from devices, from flash
memory etc. where you actually need to manipulate every bit accurately.

Fourth case - situations in which you have a scalar quantity, and do not care
about positive or negative.

Overflow is a separate issue and you must either make sure you either know the
range of the data and pick an appropriately sized storage type, or explicitly
check for overflows.

~~~
rbehrends
> Fourth case - situations in which you have a scalar quantity, and do not
> care about positive or negative.

This is actually where you have to be really careful, because there can be
corner cases surrounding zero. E.g.:

    
    
      for (i=len-1; i>=0; i--) { ... }
    

Yes, either ints or unsigned numbers can overflow, but underflowing a natural
number is much more common.

Don't take my word for it, ask Bjarne Stroustrup or Chandler Carruth:
[http://stackoverflow.com/questions/18795453/why-prefer-
signe...](http://stackoverflow.com/questions/18795453/why-prefer-signed-over-
unsigned-in-c)

~~~
pcwalton
I think this demonstrates a problem with C-style for loops (as opposed to
iterators) more than unsigned integers.

~~~
rbehrends
The problem lies with len-1 underflowing, not the loop that uses the result.
For another example, to test congruence of x and y modulo m, you check if
(x-y) % m == 0. This also blows up for unsigned integers if y > x unless m is
a power of 2.

Even iteration is not always over containers or some other structure in a way
where the boundaries can be inferred and do not have to be computed, and not
always in an order that is implemented by an iterator (for example, some in-
place sorting algorithms).

~~~
detrino
It's a problem with C for loops. There is really no good way to write a
counting down loop using a for loop. The fundamental problem is that a for
loop is: test a condition, run a loop body, then run a step function. This is
suited to counting up loops but when counting down what you want is: test a
condition, run a step function, then run a loop body. If you use while loops
instead of for loops, you will see the two loops are symmetrical and there is
no underflow for unsigned types. See
[http://ideone.com/1ABiCw](http://ideone.com/1ABiCw)

~~~
rbehrends
I don't like C for loops, either, but this can happen with other types of for
loops, either. E.g. in Pascal:

    
    
      for i := 0 to len-1 do begin ... end
    

This is counting up, not counting down, and len-1 is still going to be either
2^k-1 or result in an error when you're using unsigned integers.

While loops also don't fix it (not to mention that they have their own
problem, such as forgetting or misplacing the iteration step). The primary
issue is that len-1 is underflowing. Yes, you can avoid calculating len-1, but
by that token, no error is ever a problem, because they can all be avoided
with enough diligence and foresight. In that universe, Heartbleed never
happened and the Ariane 5 never blew up. It is, however, not the world we live
in.

~~~
detrino
That's a representation problem. C/C++ use half open ranges and have no
problems with unsigned integers.

This is also a non-issue in C++ as you have iterators and counting loops are
easy to abstract away using counting iterators or <algorithm> style functions.

------
bsaul
Every time i look at this language feature, it seems like a dream come true.
Yet, i stopped believing in santa when i was 4 so could anyone here points at
its ugly parts ?

~~~
J_Darnley
This is the first time I've heard of Nimrod and being an amateur C user these
are the parts I don't like:

\- No curly braces around anything.

\- Whitespace seems to be important, just like python.

\- Some nonsense about unsigned integers.

The best thing I saw was that it has C's explicit-size integers. The one thing
I wish every C program would use rather than having configure guess which
basic type it should use.

~~~
Dewie
> \- No curly braces around anything.

Do you find curly braces to have some aesthetic? That you like to see it in
code for its own sake?

~~~
mahkoh
Yesterday I reported a bug which had already been fixed several weeks ago but
reappeared in a new version.

After looking through the original patch and the current version, I found that
the bug was caused by significant indentation. The maintainer had decided to
add comments and accidentally indented the code one more level, making it part
of an if branch. Braces would have prevented this.

------
cju
I recommend to those who tried only the 0.9.2 version to check the new 0.9.4
as there has been a lot of improvements (Release note: [http://nimrod-
lang.org/news.html#Z2014-04-21-version-0-9-4-r...](http://nimrod-
lang.org/news.html#Z2014-04-21-version-0-9-4-released)).

~~~
skrebbel
wow, async/await, lambdas.. really nice! lovely showcase for the macro system,
too.

------
maikklein
I saw that you can even generate C++ code from nimrod and that you can
automatically generate c wrapper with c2nim, but how does it play with C++?
Can you easily use C++ libraries in Nimrod or do you have to write a C
interface?

~~~
dom96
C wrappers are still generally better supported, or at least that's what I
assume because that's what most people still use. I haven't personally tried
wrapping any C++ code yet. c2nim does support C++ now so in theory it should
be just as easy as wrapping C.

------
heinrich5991
How does Nimrod compare to Rust, in terms of goals?

~~~
dbaupp
Rust focuses _very_ much on low/no-overhead memory safety (especially memory
safety without a GC), while Nimrod seems to be more focused at more convenient
low-level programming, but without quite such a strong push for memory safety
and reliable very high performance (e.g. GC is compulsory for safety).

That's not to say that Rust isn't convenient, but the quest for strong memory
safety & performance guarantees doesn't come for free: satisfying the borrow
checker can get a little tricky at times.

An example of this: Rust's type system is designed to allow things like
building a safe shared memory abstraction[1], that is, a shared memory type
that enforces non-thread-safe data can't be shared without being inside a
mutex. My reading of the Nimrod FAQ[2] ("An unsafe shared memory heap is also
provided") implies this isn't (as easily) possible in Nimrod.

(Disclaimer: I know a lot of Rust, but very little Nimrod.)

[1]: [http://static.rust-
lang.org/doc/master/sync/struct.Arc.html](http://static.rust-
lang.org/doc/master/sync/struct.Arc.html)

[2]: [http://nimrod-lang.org/question.html](http://nimrod-
lang.org/question.html)

~~~
pcwalton
> My reading of the Nimrod FAQ[2] ("An unsafe shared memory heap is also
> provided") implies this isn't (as easily) possible in Nimrod.

Nimrod's GC is not thread safe, so you have to use raw unsafe allocation and
deallocation in order to share objects between threads (last I looked anyway).
This is in contrast to Rust, for which memory safety is important even in
multithreaded scenarios.

~~~
rbehrends
Right now, Nimrod uses thread-local heaps (similar to what Erlang does).
Threads can communicate via channels, and you can access global variables or
the shared heap unsafely if that is needed for performance.

My understanding (from talking to Nimrod's author) is that the concurrency
model is still being finalized, but that safe shared memory is going to be
part of it.

------
idlewan
If you're interested in Nimrod's performance, it's really good:
[http://codegolf.stackexchange.com/questions/26459/how-
high-c...](http://codegolf.stackexchange.com/questions/26459/how-high-can-you-
go-a-codingalgorithms-challenge/26528)

~~~
rbehrends
As the person who wrote that: the speedup here is primarily due to using a
smarter algorithm, though Nimrod helped in keeping the constant factor low.

I expect that one could get the same performance in C, though unrolling the
top levels of the recursive search would be a bit more cumbersome and having
efficient bound checks for arrays in Nimrod helped in debugging some variants
of the algorithm.

In short, the benefits of Nimrod here were expressiveness and safety rather
than raw performance (though having performance of optimized code that is
competitive with C hardly hurts, either).

------
reddit_clone
>In other words, C gives you a combined hammer and gun, while Nimrod gives you
a separate gun and hammer.

That made my day

------
egeozcan
I love working with Nimrod. What it lacks is some documentation. For example,
if you want to use PostgreSQL with it, the only documentation you can find is
this: [http://nimrod-lang.org/postgres.html](http://nimrod-
lang.org/postgres.html)

~~~
dom96
There is also [http://nimrod-lang.org/db_postgres.html](http://nimrod-
lang.org/db_postgres.html). But I agree that documentation is an area we need
to improve on!

------
inglor
Why would I use Nimrod and not C++? C++ matured quite a bit over the last 20
years and I'm not sure what advantages Nimrod has over it. The tutorial
mentions C++ a lot of times but does not mention any advantage for Nimrod.

~~~
dmunoz
I only know a little bit about Nimrod. My understanding of it is limited.

That being said, I believe a big draw is its metaprogramming abilities. In
Nimrod, metaprogramming is done using Nimrod. In C++ you have the very
limited, backwards compatible to C, C++ preprocessor and template
metaprogramming. C++ is progressing slowly towards metaprogramming in C++ with
constexpr. constexpr support is much stronger in C++14.

D is similar. In D, the metaprogramming language is (I believe) D itself, or
at least very similar to it. D also has strong support for compile time
function execution.

Nimrod also does a lot more to guarantee safety. C++ can only do so much, due
to its (mostly) backwards compatibility to C.

------
jessaustin
It's quite annoying that the "cheat sheet" table at the bottom is so narrow
that one must scroll it back-and-forth to see all three columns.

~~~
dom96
That seems to be the result of Github's recent wiki redesign
([https://github.com/blog/1828-wikis-now-with-more-
love](https://github.com/blog/1828-wikis-now-with-more-love))

------
plg
I read the title too quickly and I thought it said

C for nimrod programmers

