I love Python. I love the idioms and the syntax. I love the flexibility. I don’t love the status of multicore python programming. I don’t love the speed. I want a good builtin coroutine system that enables both async IO and multicore programming. I’m not wild about tulip.

So I’m looking to add another language or two. I started by taking some time to look at Julia, which looks nice, but I also took a look at a few other things.

I applied my standard Peano-addition toy problem, which I admit doesn’t really tell you much about the performance of a language except if/how much tail calls are optimized, how fast its increment/decrement operators are, and how optimized the loops are out of the box. But it translates pretty well to any language and gives you a taste of the syntax and build process. I used iteration instead of recursion if the language doesn’t support tail call optimization – which is every language here except Scheme and the not-yet-complete Haskell version. If you’re all Haskell-y, all the time; maybe you can help me with my code, the compilation, or the running. I also did a Clojure version, but Clojure doesn’t seem well suited for writing command-line utilities because of the long java runtime startup. I’m also not going to leave a java engine running in the background to handle this kind of thing. So I moved that code (with some minor adaptation) to Scheme and compile it with CHICKEN.

Here are the run times for my sample code. These times aren’t likely to be fair. I turned on -O5 for the Scheme app and didn’t even look into optimization for any of the other languages. In fact this is the proper size of the grain of salt you should take with these numbers.

Language | Peano Addition Time -|- Go | 0.07 seconds CoffeeScript (under Node) | 0.28 seconds Python (pypy) | 1.15 seconds Scheme (CHICKEN compiled) | 1.28 seconds Julia | 15.66 seconds Python (cPython) | 29.28 seconds

Python

I love Python. PyPy helps with the speed bit. Here’s the code

#!/usr/bin/env python
	
a = 64000000
b = 64000000
	
while True:
    if a == 0:
        break
    a -= 1
    b += 1
	
print b

Here’s the run time:

  • Under cPython 2.7.5: 29.28 seconds
  • Under PyPy 2.2.1: 1.15 seconds

Julia

I’m excited by the Julia language. It’s based on a JIT compiler and the syntax is pretty nice: it has optional types, promising multi-processing features, useful metaprogramming ability, reasonable (but slow) exception handling, and iJulia. There is currently no “precompiling” a Julia program yet and the interpreter startup on OS X is pretty slow (5.07 seconds for 0.3.0-prerelease+2703 and 3.74 seconds for the 0.2.1 release). Here’s the code:

#!/usr/bin/env julia
	
a = 64000000
b = 64000000
	
while true
    if a == 0
        break
    end
    a -= 1
    b += 1
end
	
println(b)

Here’s how it performed:

  • Under 0.2.1: 15.6 seconds
  • Under 0.3.0-prerelease+2703: 20.0 seconds

Go

I’m excited by Go too. I like the speed. I love the multiprocessing. I’m OK with the syntax, but think bad things about it behind its back. I’m cool with the one true way of go fmt. I want more libraries. I think I want shared libraries. I want generics. I want try/catch exceptions. If you pull that “exceptions aren’t exceptional” line, I’ll reply via knuckle sandwich dispatch.

Here’s the code:

package main
	
import "fmt"
	
func main() {
	var a = 64000000
	var b = 64000000
	
	for {
		if a == 0 {
			break
		}
		a -= 1
		b += 1
	}
	
	fmt.Println(b)
}

Here’s how it performed:

  • Using “go run”: 0.56 seconds
  • Build then run compiled: 0.84 seconds
  • Run precompiled binary: 0.07 seconds

CoffeeScript under Node

CoffeeScript is a wrapper for the JavaScript language that makes JavaScript tolerable. Without it, I’m this kind of JavaScript programmer. Here’s the code:

a = 64000000
b = 64000000
	
while true
	if a == 0
		break
	a -= 1
	b += 1
	
console.log(b)

It was fast:

  • Compile CoffeeScript to JS, Run result with Node: 0.46 seconds
  • Just run the “compiled” JS with Node: 0.28 seconds

Scheme (compiled by CHICKEN’s csc driver)

Why not. (We (wont (talk 'much (about (the (syntax, (because (that's (obvious))))))))) This started as Clojure, but after all the uberjarringly bad Java startup times, I switched to Scheme, compiled by CHICKEN. Performance isn’t too bad. Note that I abuse recursion, because LISP gives me enough rope, and frankly because I’d have to look up a way to iterate instead.

The Scheme code:

(define peanoadd 
	(lambda (a b)
		(if (zero? a) b
		(peanoadd (- a 1) (+ b 1)))))
	
(write (peanoadd 64000000 64000000))
(newline)

The time:

Compiled with csc -O5.

  • Compile & Run: 1.76 seconds
  • Run Compiled Code: 1.28 seconds

Haskell

I also wrote a Haskell version but I haven’t yet taken the time to deal with the stack overflow I encounter. I still need to learn me a Haskell. Here’s what I’ve got so far:

module Main where
	
peanoAdd     :: Integer -> Integer -> Integer
peanoAdd 0 b = b
peanoAdd a b = peanoAdd (a - 1) (b + 1)
	
main = do
	let result = peanoAdd 64000000 64000000
	print result