

Experiments with Nimrod - Cyther606
http://ziotom78.blogspot.com/2014/01/experiments-with-nimrod.html

======
rdtsc
Performance of Nimrod is very impressive.

There was another post a year or two back, where someone was making a small
game and found Nimrod to be the winner, after C/C++ (sorry lost the link).

Garbage collection is also pretty interesting.

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

There is a real-time feature to it, it basically says "collect garbage but not
more than X microseconds a time". That would be useful for some applications
like games, hardware controllers, low latency audio or signal processing.

I wish some big company (Google or Mozilla) would have taken a look at Nimrod
before going and building their own language and then promoted and marketed
it. I guess that almost never happens. Is that arrogance, not invented here
syndrome, legal issues with copyright...?

And as much as I like Nimrod, I feel there also a bit of language-fatigue in
the community. There are so many new-(ish) platforms and languages (Go, Rust,
Swift, Dart, Clojure, Scala, Julia, Elixir). Yes they all have cool things and
are slightly different but I wish there were less new languages and more
stable languages, with better documentation, and a large library ecosystem.

~~~
pcwalton
> I wish some big company (Google or Mozilla) would have taken a look at
> Nimrod before going and building their own language and then promoted and
> marketed it. I guess that almost never happens. Is that arrogance, not
> invented here syndrome, legal issues with copyright...?

Rust has different goals than Nimrod (memory safety without garbage collection
and data race freedom—both of which are important for writing a parallel
browser engine).

~~~
jimmaswell
Why is the absence of garbage collection particularly important for a web
browser engine? I've had good experiences with a few intensive games and
programs that use GC'd environments such as the .NET runtime, so I don't think
performance would be much of a reason that you can't have GC with a web
browser. Is it security (old data left visible in ram)?

~~~
pcwalton
To be precise, _global_ garbage collection is the big problem: when one tab is
collecting garbage we don't want to stall the other tabs. At the same time, we
need to be able to share objects between threads in a fully memory-safe
manner. Desirable is the ability to do this without any runtime overhead
compared to C++ (e.g. barriers or pauses), because any browser engines will be
compared head-to-head in terms of performance against engines that pass raw
pointers around during layout, etc.

I know of no GC algorithm that is memory-safe and thread-safe, avoids stopping
all threads, is barrier-free, can deal with cycles, runs on commodity consumer
hardware without a kernel extension, and is competitive in performance with
typical C++ memory management schemes.

Besides, once you have data race freedom (important for us) you are already
most of the way to memory safety without garbage collection. (For more, see
[1]).

[1]:
[http://smallcultfollowing.com/babysteps/blog/2013/06/11/on-t...](http://smallcultfollowing.com/babysteps/blog/2013/06/11/on-
the-connection-between-memory-management-and-data-race-freedom/)

~~~
seanmcdirmid
The link sounded like linear types, which they talk about at the end. There
are plenty of apps that don't need full on C++ performance and can't afford
the dev costs anyways. Garbage collection isn't the big problem for these
apps; getting the code to work is.

The analogy between memory management and data race avoidance is apt, but not
in just the way you're thinking. We can also build slower garbage collection-
like systems for automatically handling data races, further improving
programmer productivity [1]. In this case, unrestricted sharing is still
allowed, and the run time just takes care of it (for a price, of course).

[1] [http://research.microsoft.com/en-
us/people/smcdirm/managedti...](http://research.microsoft.com/en-
us/people/smcdirm/managedtime.aspx)

~~~
Jweb_Guru
Having actually read the paper...

Firstly, it isn't even actually published yet, so I'm not sure why you'd use
it as an example of why people shouldn't have tried other knwon techniques for
avoiding data races.

Secondly, there are plenty of already known ways of mitigating data races in
managed languages (incidentally, the "managed time" paper you describe
actually has a really good survey of availabile mitigation techniques).
Haskell is normally data race free. So is Erlang (99% of the time). Databases,
and transactional systems in general, give you _far_ more guarantees than
simple data race freedom (especially in the face of high concurrency) without
making it ludicrously hard to reason about (if you use a strong enough
isolation level), and they do that through managed software.

All of these systems, as good as they are, have very important tradeoffs: *
They trade off pure speed for higher throughput (generally speaking). * Even
if they are totally race condition free internally, they are still susceptible
to them when they interact with external systems (even other instances of
their own runtimes). * They require you to significantly constrain how you
write code in order to make it actually satisfy these properties.

And while points (1) and (2) actually have lots of similarities with the
tradeoffs of garbage collection as a technique, point (3) does not (well, I
guess you could argue about pointer math :)). I believe that this represents
irreducible complexity in parallel programming.

As far as I can tell, Glitch is not different from transactional database
systems, and arguably much worse since it's a pretty naive implementation.
Restriction to commutative state updates is attactive in many cases, and they
are easy to optimize, but there are _tons_ of updates that aren't commutative
(look at a reasonably complex database system, some of which actually do have
notions of commutativity). Tasks are just another word for transactions (as
you can see, boundaries are explicitly specified). Glitch claims it is
different from this because they "do not address ordering changes made inside
a transaction, nor coordinating multiple causally connected transactions into
larger-scale processes." I find these claims very strange because at least as
used in databases, explicit orderings are actually pretty uncommon (that's the
whole point!) and Glitch is going to have the exact same issue if you try to
use it with the rest of the system. Similarly, the article discusses how
transactions need to be aborted and retried, but Glitch already does this.

Because the system does not have any knowledge of global ordering, replay
order is fairly suboptimal (this was found to matter in practice in
PostgreSQL, for example, which avoids lots of potential deadlocks and
incorrectly reported serialization failures by reordering dependencies in this
way). Additionally, to preserve all its invariants, the program must remember
old state until the entire system is in a consistent state, which will lead to
substantial memory ovheread over other systems. Fixed-point iteration is also
intrinsically quite slow in many cases--I don't see any runtime analysis here
but I suspect in practice it is going to be a far cry from even naive garbage
collection techniques. Since the only reason to actually _do_ concurrent
programming is for performance (except, again, where interacting with external
systems, at which point your runtime can't help you anyway) I don't think this
can be usefully handwaved away. Unlike MVCC, Glitch does does not preserve an
easily _accessible_ view of old state (it's there but requires calculation to
reach), I think this problem is not going to go away with a better compiler as
the authors claim.

Most importantly, though, managed time fails point (3). From a cursory read
through the paper, I'm pretty sure it also suffers from the same potential
livelock issues that are the reason databases don't just restart transactions
automatically (the phrase livelock doesn't occur anywhere in the paper but I'm
assuming the authors are aware of it). It also seems to me that it would not
be hard to create cyclic dependencies that freeze up your program forever;
while this isn't necessarily _worse_ than proceeding with totally invalid
state, that doesn't give me great confidence that I can simply "plug and play"
Glitch and hope for the same behavior I'd see in a sequential system. Most
damningly, to quote the article:

"YinYang can be used to implement user interfaces, games, and even a compiler,
but it is not clear how to express simple things like an in-place bubble sort!
Many classic algorithms depend upon re-assignment in one time step and thus do
not naturally transliterate well into Glitch; similar limitations occur in
single-assignment languages."

Just to be clear: I'm a huge fan of transactions. I think they're great. I
would love first class support for transactions in most programming languages.
But while I think they're solving a much _harder_ problem than garbage
collection is (and certainly harder than the very restricted problem of
preventing data races, which can be done much more easily if performance
really isn't a factor by making every update atomic), calling them "automatic"
is a bit of a stretch.

~~~
seanmcdirmid
Thanks for reading the paper, the publish date is October 2014, I'll present
it at onward! next month. It's a lot too go through so Ill need to pick
through this more carefully. But the feedback is most definitely useful.

Haskell is data race free because they just avoid state. If shared state is
involved, it has the same problems and needs to deal (e.g. Via STM). Glitch
also gives you far more guarantees than data race freedom (consistency being
the buggy).

(3) depends on the technique. There are bondage approaches, but there are
approaches that allow more flexibility. Glitch is in between that.

Transactions have no notion of replay: the transaction fails and then what?
Also, transactions are atomic, whereas tasks in Glitch are continuous: if
something changes over time, a task will be replayed..a transaction has
already been done and you have to manage change very time your self. This same
replay mechanism also washes out data races.

Glitch doesn't suffer livelock problems because effects are not undone until
"after" a replay (removing effects that haven't redone) whereas transaction
just undo everything when they fail. This is a huge difference in terms of
making progress! Glitch is not coming from the database field, but rather from
general programming semantics where effect ordering requirements are quite
common.

The problem with optimal orders is that you don't know what they are usually
appriori. Many systems, like flapjax, require optimal orders because execution
is not idempotent. Rather than make that requirement, we instead make
execution virtually idempotent through logs. We "could" execute in a more
intelligent order as an optimization, but it's not required (I've indeed found
some tuning in scheduling necessary for performance).

The past is only remembered as long as it's needed for computing a consistent
view; it can be thrown away after. You could also remember the last to do Bret
victor style debugging, which is why the feature mostly exists (we could just
make sure everything was consistent before processing the next event
otherwise), or for distributed processing where computers might proceed at
different paces (and therefore will have to agree in a baseline time where
none has a task to replay that could change state before it). This is all
quite standard in virtual time systems.

Pardoxes will cause continuous replay, like writing x = !x, it has no
consistent interpretation. It doesn't freeze up the system, you can always
change the statement to fix the problem (the UI remains responsive).

------
ilaksh
Nimrod has amazing performance, extremely clear syntax, and advanced
metaprogramming features. That combination is unmatched in programming
languages. It is a significant advance.

Yet, the Wikipedia editors continuously delete the Nimrod programming language
article, claiming Nimrod is "not notable".

Wikipedia editors will say that there aren't enough third party articles or
something, but that isn't true. And then they will say, yes, this is notable
compared to quite a lot of other garbage or trivia that has articles on
Wikipedia, but just because "other crap exists" isn't an excuse to allow this
article.

I think that notability has to be a relative concept, and Nimrod is notable.
At this point its just small-dick Wikipedia editors asserting their control.
Either that or some editors are invested in other programming languages and
are trying to stop this one from becoming mainstream.

This proves to me that Wikipedia is utter crap. But unfortunately, we are
stuck with Wikipedia and it has quite a lot of influence. I wish someone who
had pull on Wikipedia or knew how to make it work would fix this problem. I
have tried. It seems like maybe it actually just made the editors band
together more to try to continue to keep it off, just as sort of a reaction.
Like its a group that works together to oppose anyone who isn't already an
insider.

~~~
_delirium
I don't think there'd be an objection to creating a cited article. I took a
brief look at the deleted version, and it didn't have any sources considered
sufficient. It cited two things: 1) a random blog post by someone who tried
Nimrod and liked it; and 2) an introductory _Dr. Dobbs_ article written by the
Nimrod author himself. Now #2 is useful as a supplemental source, but
typically can't be the _only_ source for a Wikipedia article. Had I run across
it, I personally would've just tagged it "needs third-party references" rather
than deleting, but which way things on the borderline go has a lot of
variance.

A better place to start would probably be to find a description of Nimrod in
some standard source—textbook, survey article, etc., and start from there,
then flesh out with supplemental sources written by the Nimrod author himself
for details. If Nimrod hasn't yet gotten solid third-party coverage despite
deserving it, the root of the problem might lie elsewhere than Wikipedia—on
scientific/technical/etc. topics, Wikipedia just summarizes the current state
of the literature, leaving _improving_ the literature as a job better done
elsewhere.

~~~
klibertp
> find a description of Nimrod in some standard source—textbook, survey
> article, etc.

No offense, but are you even aware what you're saying? You just limited
Wikipedia to describe only those new languages which come from academia and
have research on them published. Plenty of those, to be sure, but this
shouldn't be a requirement for a language to be described, IMO. Oh, and it's
apparently not, the second try (after PureScript, which is absent from wiki)
brought me to this page:
[http://en.wikipedia.org/wiki/Roy_%28programming_language%29](http://en.wikipedia.org/wiki/Roy_%28programming_language%29)
which cites oh so many serious papers. I could probably easily find tens of
articles like this on wiki - either delete them right now or stop the double
standards treatment of any one particular language. Like this one:
[http://en.wikipedia.org/wiki/Picolisp](http://en.wikipedia.org/wiki/Picolisp)
\- and I really could go on (EDIT: there _is_ a paper on Picolisp, but it's in
the external links section which made me miss it).

~~~
_delirium
The third-party sources don't specifically need to come from academia or be
research articles. Third-party sources can perfectly well be (and often are)
practice-oriented and come from industry: books from trade presses, articles
in tech magazines, etc. Tons of languages on Wikipedia with well-sourced
articles aren't from academia: CoffeeScript, Go, Clojure, TypeScript, Dart,
Arc, D, Erlang, Swift, Scala, etc.

~~~
klibertp
Wait, wait. Look at Arc article. It cites no printed ("textbooks, survey
articles, etc") materials at all. All the references in the article are either
essays by the author, blog posts or github repos. Which makes it pretty much
in the same situation as Nimrod. How come Arc has its page, and Nimrod
doesn't?

Other than that, all the languages you mentioned are either old (5+ years) or
have corporate backing, or both - and it should be obvious that we're not
talking about langs like these. Aside from Arc you failed to mention even one
language comparable to Nimrod in terms of existing sources.

Meanwhile, look at newLisp article and its references. Why does it exist? It
has four referenced sources, where one is "unreliable", one is an article
comparable to the one in Dr.Dobbs on Nimrod and two remaining ones are posts
by the author.

Look at Felix article
([http://en.wikipedia.org/wiki/Felix_%28programming_language%2...](http://en.wikipedia.org/wiki/Felix_%28programming_language%29)).
It has no source whatsoever, yet it still exists.

Same with Alice ML
([http://en.wikipedia.org/wiki/Alice_%28programming_language%2...](http://en.wikipedia.org/wiki/Alice_%28programming_language%29))
- which is probably just laziness of editors, because Alice papers were
published IIRC. Yet they are not referenced at all, and the article still
exists.

There is reference to one printed source in Io language article
([http://en.wikipedia.org/wiki/Io_%28programming_language%29](http://en.wikipedia.org/wiki/Io_%28programming_language%29)),
so maybe it should be allowed to live. However, "Seven Languages in Seven
Weeks" is not a very detailed description of any one language it covers (of
course) and I could argue it's not enough to rely on it as an only source.

Lisp flavored Erlang
([http://en.wikipedia.org/wiki/LFE_%28programming_language%29](http://en.wikipedia.org/wiki/LFE_%28programming_language%29))
is apparently well sourced, as the article for it exists. Not even one of the
sources was ever published in print.

Same with Hy
([http://en.wikipedia.org/wiki/Hy](http://en.wikipedia.org/wiki/Hy)) - all
sources are blog posts and similar.

Look, I could really go on. Studying obscure languages nobody heard about is
my hobby and I have lots and lots of examples, but I'd hope the above is
enough to show you a "double standard" displayed here by Wikipedia editors.
Either remove all of those - and no, I'm not going to help you with this - or
stop bullying some languages without any reason at all.

------
Symmetry
I keep thinking that in my ideal robot software stack the firmware would be
written in Nimrod, the signal processing and planning in Rust, and the
business logic in Go.

In particular, I really like Nimrod's ways of expressing that various
computations are done at compile time and their macro system.

~~~
blt
Hmm, I really dislike cross-language interop so I would prefer to use Rust or
Nimrod for everything. Why do you prefer Nimrod for firmware and Rust for
signal processing/planning?

~~~
Symmetry
So basically, what I'm doing above is replacing C with nimrod, C++ with Rust,
and Java with Go.

Rust has a certain amount of extra complexity needed to provide powerful zero-
overhead abstractions. Those abstractions would be very useful for the signal
processing and planning and those are areas that are performance critical.

But for code that isn't so performance critical that you're always thinking
about where everything is in memory, you might as well just use a garbage
collector and it's easier if that's built into the language. Language design
involves tradeoffs between features and complexity.

And for the embedded side I don't need that much abstraction, and again I
really like Nimrod's way of letting you talk about things specified at compile
time.

Cross language interop really isn't a concern since these parts are all
talking to each other across sockets or over USB. Team training is a concern
but I'm actually the only person here who works in all three areas so it's not
a huge one. Of course, the lack of Rust and Go ROS bindings is certainly a
concern but we're talking about an ideal stack here. :)

~~~
blt
Great answer, thanks. I didn't realize that robots use IPC between the
planning/DSP and firmware layers. I'm also surprised that Rust doesn't have a
strong ability to talk about compile time computations.

~~~
Symmetry
I'm looking forward to ROS2 using DDS, which will give zero copy IPC for nodes
on the same computer. [1]

I wouldn't say that Rust is bad at talking about compile time versus runtime,
just that Nimrod is better. This throws a compile error in Rust, for instance:

    
    
          static FOOBAR: int = if 2i > 1i { 10 } else { 20 };
    

But this doesn't in Nimrod:

    
    
      when 2 > 1:
        const FOOBAR = 10
      else:
        const FOOBAR = 20
    

And that's all because Nimrod added this 'when' keyword distinct from 'if' for
stuff that gets computed at compile time. I wouldn't need something like that
in a non-embedded context (I guess it's used for specializing to a given
operating system by the creator?) but I'll happily use it.

[1][http://design.ros2.org/](http://design.ros2.org/)

~~~
dom96
Keep in mind that Nimrod will also try to evaluate normal code at compile-
time, so the following will work fine:

    
    
        const FOOBAR = if 2 > 1: 10 else: 20

~~~
Symmetry
What I'd actually be doing is more like:

    
    
      when ROBOT_VER == 32:
        type TSonarAddresses = array[0..3, int]
        const sonarAddresses: TSonarAddresses = [1,2,3,4]
        ...
      elif ROBOT_VER == 33:
        ...
    

and stuff like that.

~~~
dom96
I see. Good, that is precisely what 'when' should be used for :)

