The speed, size and dependability of programming languages
gmarceau.qc.ca
gmarceau.qc.ca
http://gmarceau.qc.ca/blog/uploaded_images/size-vs-speed-vs-...
V8 has propelled JavaScript into the coveted bottom-left corner, which is awesome. SquirrelFish Extreme should be right up there with it, if it were included.
And it's more expressive than scala and f#? Something's gotta be wrong there..
My own benchmarks that I run on our heavily algorithmic long running code consistently show Java about 10% to 20% slower than gcc (C++) and memory usage about twice that of the C++ implementation (excluding the JVM memory itself). C and C++ performance depends heavily on avoiding malloc/new. C/C++ code that gratuitously allocates and frees heap memory tends to be much slower than Java code.
It's also interesting how the LuaJIT star has about the same shape as the Lua star, but with 1/3 the width (which is consistent with my experience); Psyco relates similarly to Python. Surprisingly, the Lua star's center appears to be at the same X as GHC's, but lower down, and LuaJIT's overlaps OCaml's. While I can accept well-written Lua being approximately as expressive as Haskell (depending on the problem), I don't think it's in quiiiite the same ballpark as OCaml, speed-wise.
The most interesting shape, to me, is Io's: While the default performance seems pretty poor (the right edge meaning 8x as slow as the left edge), there are bands shooting all the way to the left, without adding any real height. I don't have any experience with Io (I'm curious, but have never had success porting it to OpenBSD/amd64); can anybody here comment on this?
In all fairness, neither do most people promoting C++'s performance-at-any-cost design.
I think a large spread in the performance correlates with requiring skill level, though -- it means that some people using the language get good results, but that many also get very bad ones. Ruby is a really slow language ("reasonably good" < great), but it's still good enough for many purposes, provided your algorithms are reasonable.
If dealing with Ruby's syntax were easier, Ruby implementations would progress faster.
"It's a slow language," implies that there's something special about Ruby that precludes (relatively) fast implementation. There's nothing special about Ruby like this. Ruby is a very nice remix of language features that existed before. Getting a language to be fast can require many iterations. Ruby's syntax is a high barrier to entry to implementers, so fewer eyeballs have been looking at the problem.
Contrast this with Smalltalk. http://news.ycombinator.com/item?id=619398
Smalltalk was designed to be quickly implemented by a single programmer. Implementing a "Bluebook VM" was treated as a rite of passage for support engineers for at least one of the vendors. As a result, people have implemented many, many variations on Smalltalk. (Including an VM with built-in OODB, another that can compile down to a C++ compatible DLL indistinguishable from one written in C++, another that ran on the old Palms, one with optional typing, and many others.)
I think it's fair to say that writing a Ruby VM is probably an order of magnitude harder.
The existence of LuaJIT (http://luajit.org/luajit.html) supports your argument, I think.
There seems to be a mistake. If you compare Io to JRuby [1], you'll find that Io is always the slower one, even though the picture in the article suggests otherwise.
[1] http://shootout.alioth.debian.org/gp4/benchmark.php?test=all...
"yarv" is the graph that represents what is now Ruby 1.9, "ruby" only represents Ruby 1.8
Few solid conclusions can be drawn: small performance benchmarks are hardly indicative for both the code size and the performance of most actual projects in a language.
I found one minor inconsistency: Lua has all these but is still colored blueish.
It seems like a small thing syntactically, but languages that return the result of their last expression by default (I think of them as "expression" languages), and that require an explicit block for side-effects (begin in Scheme and OCaml, progn in Common Lisp, etc.), tend to get idiomatically used in a functional manner, while languages that default to a series of statements with side-effects and require an explicit return at the end ("statement" languages) typically do not. While you can use several of the latter languages for functional programming, only the former are functional "by default".
Saying "function(x) return x + 1 end" is a tiny bit more trouble than "fun x -> x + 1" or "(lambda (x) (+ x 1))", so while lambdas still get used where they're the best fit (as arguments for map or filter, for example), they're less common overall. Defaults influence a language's overall style at least as much as what's theoretically possible. Python's concept of what's "pythonic" seems to be the most explicit acknowledgement of this.
Incidentally, I would love to see a language that crossed Lua with the ML family: a small, portable, clean implementation that interfaces easily with C, but with type inference, ML's top-notch module system, and (ideally) Haskell-style type-classes. OCaml is such a good language that I'm willing to tolerate its warts, but I'd strongly prefer a minimal ML-like language. (FWIW, I haven't used SML, though that's just because I do most of my programming on OpenBSD/amd64 and the smlnj port is i386 only.) When standalone, Lua is best suited to small/medium projects. Its historical emphasis on embedding in an existing project has made a module system for standalone use a bit of an afterthought.* As a project gets larger, static checking and stabilizing the module interfaces becomes far more important, and this is one area the ML languages really excel.
* For a good summary, see "Almost Good Enough to Scale: A Lua Mail Handler and Spam Filter" (http://www.lua.org/wshop08.html#ramsey)
We have a bunch of code that compiles to both Common Lisp and Javascript, and those nasty "return" statements are one of the two biggest mismatches between the two languages (the other being Javascript's weird semantics around null, false, 0, and ""). One of these days I intend to try inserting them all automatically.
function(arg1, arg2, argn) return some_expr end
to the much more concise |arg1,arg2,argn| some_exp
makes me wish they were part of core Lua.I've postponed learning Javascript until recently, because my work hasn't usually been web-oriented, but it's interesting how similar Javascript and Lua are. They seem to have been aimed at the same target, but for historical reasons Javascript's development got frozen early, while Lua had time to iron out many similar design flaws.
(In Lua, undefined and null are both nil, nil and false are "false-y", and everything else, including 0 and "", are truthy.)
JS is not so bad. We're lucky that what we're doing (writing high-level FP code that compiles to JS and runs in pretty much every web browser in the world) is doable at all.
JS even has its own version of progn: "(a,b,c)" evaluates to c (after evaluating a and b). We use that pretty heavily. Alas, it has two problems: there are some things you can't do inside the block (like declare new variables or have for loops), and it makes the JS harder to read and debug. Otherwise we'd probably just compile everything that way.
Every now and then we hit upon a new abstraction that lets us remove another chunk of ugliness from our code (while still generating acceptable JS) and I'm hoping that the trend will continue, especially if we can get rid of all those "return"s.
But I agree, it should be colored green in the "functional programming" section.
That supports a common conviction held by fans of functional programming: if all of the years of arduous optimization that have been poured into GCC had instead been poured into (say) GHC, then Haskell would be even faster today than C is.
That is, to many people functional programming languages seem to have more potential for performance than lower-level procedural languages, since they give the compiler so much more to work with, and in the long run a compiler can optimize much better than a programmer. But so much more work has been put into the C-style compilers that it's hard to make a fair comparison. It's still hard, but this experiment seems to give some solace to the FP camp.
It's not merely that the ghc developers have been insufficiently clever and diligent.
If you've looked at Peter Norvig's spell checker shootout you won't be surprised much. Ex., the story on Common Lisp and Scheme implementations is the same here: MzScheme is the mediocre best of an unimpressive lot. (I want to see Clojure and Arc on this.) Python looks great again. F# looks weak here but wins big in the spell checker with reasonable-looking code. Sounds interesting.
What's the deal with Squeak? I had thought that it very concise.
The meta-message here is best of all: people are measuring language conciseness.
Also, it's worth noting that the features in a language that make large systems' codebases manageable (such as good module systems) are different from the features that allow you to pare down small scripts further. It's hard to show features supporting conciseness-in-the-large in a one page benchmark, so IMHO the latter is often greatly overemphasized. Being able to knock 2 lines off 20 is often just a parlor trick, though, while 50kloc off of 200kloc can mean life or death for a project. The programming world would be a happier place if the size of every legacy C++ / Java codebase were cut by a double-digit percentage.
> Well, arc's running on top of MzScheme, so it's likely to be a bit slower.
I'd be interested to see how Arc fares on the code-size axis.
I'd try it, but I don't know Arc (or Lisp yet, for that matter). If someone here knows Arc and wants to see it in the Shootout, I suggest they look into the faq: http://shootout.alioth.debian.org/u32q/faq.php
The productivity comes from reading and re-using the code that has already been written rather than duplicating stuff.
Maybe I just can't read, but Ruby 1.9 appears to still be slower than Perl on more than half of the tests. I wouldn't call that "Perl-beating".
However don't count your chickens just yet with regards to Ruby 1.9 being "Perl-beating" ;-) Don't you think its odd that Perl 5.10.0 sits only just above Ruby 1.8.7 in the current alioth shootout? Quick look at the tests and I can see a problem with a known 5.10.0 speed issue bug. Fixing this in a quick local test here makes all the difference ;-)
It makes all the difference to that one benchmark - not to the overall situation.
Which is interesting considering Perl beats PHP on both axis in the linked article.
mlton may not allow separate compilation (it does whole-program optimization at least), and it's pretty slow even on small stuff, but if you were really using just the Standard ML language, you could use a faster compiler for development. I'd probably want to use some extensions, and I wasn't sure if the intersection of mlton's extensions with some other implementation could satisfy me.
I don't have really concrete experience with SML, just OCaml, which also has its share of warts. It's a fantastic language in certain niches, though; generally, the sort of niches for which dynamic / "scripting" languages are usually a poor fit. (I wouldn't write a serious compiler in Python, for example.) They're very complementary.
I think the ML family has a lot of advantages, but the community is pretty closely tied to academia (much like Haskell, but without the buzz). While that in itself is probably neither good nor bad, in this case a lot of the terminology used is especially math-y; There are many features ML has that programmers would find tremendously useful, except they're usually discussed using Greek letters, which is insular. I got a copy of The Definition of Standard ML from Amazon, hoping to get further insight into the language's design, and found it completely impenetrable. (Then again, I'm not a grad student.)
Newer languages seem to be using type inference (finally!), but as far as I know, nobody has really ran with the design of its module system.
_Purely Functional Data Structures_ by Chris Okasaki is, by far, the best collected resource, if you want to read further. (His thesis (http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf) is the kernel of the book.) Also, the fourth chapter of Developing Applications with Objective Caml (English translation: http://caml.inria.fr/pub/docs/oreilly-book/) discusses functional and imperative styles' strengths and weaknesses.
Reducing everything to runtime benchmarks obscures how, in practice, the trade-off is often more like "it was a huge pain in the ass to get working without bugs, but it's 2% faster" versus "it took twenty minutes and was correct on the first try". (Also, whether or not you use it in production, OCaml rules for prototyping complex data structures, in the same way Erlang does concurrency and C++ does linking errors.)