Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

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

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.



Well, the two Google languages you mention there are philosophically _very_ different than Nimrod. Dart has always been specifically targeted as a Javascript alternative/successor, and Go has a strongly minimalist, "one way to do it" inherited from its Plan 9 heritage.

Also, Google hasn't done very much to promote either Go or Dart. Neither of them are alternate languages for the Android platform, for instance. Chrome doesn't natively support Dart, even though the functionality exists (in Dartium). They're more like open-source projects originating in and supported by Google, as opposed to official Google products.

The history of biological evolution is marked with periods of rapid diversification followed by mass extinctions and consolidation of remaining lineages. I think programming languages follow the same trend. We're in a period of diversification right now, and at some point in the future a handful of today's newcomer languages will be the hoary old relics that people are trying to get away from.


> 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).


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)?


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...


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...


> 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.

Yes, but I'm not sure how that's relevant considering that rust is attempting to compete against C++. This is definitely an area where statically analyzable performance bounds are really important, including memory management, and GC becomes very difficult to defend. GC is not the only way to remove manual memory management, and if performance is a priority you'll be hard-pressed to find a GC that naturally has the tradeoffs your particular algorithm will need to work optimally.

In the end, GC solves a different problem than Rust does. GC says "I never want to think about memory." Rust says "I never want to deref a null pointer."


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.


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).


> but I wish there were less new languages and more stable languages, with better documentation, and a large library ecosystem.

Um... Pick one of those and write a library or docs for it?

Languages with google-level financial support will live no matter what (as long as the company behind them exists), but even in case of those languages any help is always welcome. For languages like Nimrod, which IIRC is done entirely by just one guy, you can make a real difference with 15 minutes of your time per week. There's always so much to do, and since no one is paid to do it, some things (docs, in particular) are often lacking, that's true. But the only one who can make your wish true is you: just start contributing to one of the languages.

As a side note, this is why I love new, small, niche languages. Even relatively simple contribution to them makes a visible difference and with some more work you can really influence the shape of the language. And you can really be the first to do something meaningful, like http client/server library. Writing such things is fun, but in every other language they are written already and reinventing them would be a waste of time. Not so in languages like Nimrod or Julia, where they would be valuable contributions.

Anyway, just pick one of the languages, learn it and contribute to it and you'll see it mature quickly (it will still take years, but thanks to you not decades).


Couldn't agree with what you have said more. I wish more people looked at things this way. I personally have had a lot of fun contributing to Nimrod because like you said it is very easy to contribute something meaningful. I wrote a lot of the standard library modules, including http client/server modules and more. It wasn't only fun but it was also a very good learning experience and because the community is still quite small getting real-time help from the creator of Nimrod is very easy.

So instead of writing the 100th ORM for Python write the first one for Nimrod :)


> 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 ...

Welcome to the 80-90's, before the likes of C, C++, C# and Java kind of wiped the others out of most corporations radars.

I like being brought back into those days.


People act surprised when a compiled language approaches C performance. I don't understand why. Any language that compiles to machine code, doesn't store every object on a GC heap, and has C-like function call semantics should be bound by the performance of its optimizer and not anything inherent in the language. Nimrod transpiles to C so it gets the C compiler's optimizer. Rust uses a LLVM backend so it gets the LLVM optimizer. It should be surprising if these languages don't approach C performance.


Swift and Rust have similarities.

Swift is, I believe, designed with an eye towards interop with Objective C. Rust pcwalton has already addressed.

- Dart is for JS

- Clojure is a GC'd JVM Lisp

- Scala is a GC'd JVM type-safe language

- Julia is specifically for scientific computing

- Elixir is an Erlang wrapper, afaik.


Nitpick: if Elixir is an "Erlang wrapper", then Dart is a JavaScript wrapper and Clojure is a Java wrapper.


Ah, OK. I thought Elixir::Erlang like CoffeeScript::JavaScript. My apologies.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: