

Tuning Concurrent Clojure - mreid
http://www.tbray.org/ongoing/When/200x/2009/12/08/WF-Tuning-Clojure

======
mcav
As a Python programmer who has heretofore found Clojure very favorably
designed, this is a little disheartening. I haven't programmed in a functional
language yet; Python has served me really well for most everything, and C/C++
has always covered gaps where I need a little speed boost.

Yet I've always seen functional languages as a real fundamental approach that
seems really elegant in theory. I have "Programming Clojure" on my Christmas
list. Something about functional languages' elegance makes me really want to
have a functional language succeed long-term. But every single functional
language I've seen so far seems to miss the mark in seemingly important ways:
Erlang with its syntax and purported string issues; Common Lisp (et. al) with
its fragmented variants (so I hear); etc.

I would really like to see a great functional language _executed well_. You
know, the whole deal: speed, interoperability, diverse libraries,
concurrency...

Maybe Clojure is it, and it just has warts to iron out. Maybe the obtuseness
that Tim Bray described here is just not "the way to do it". I hope that
functional languages aren't inherently more difficult to work with than, say,
Python.

I haven't worked with any of these functional languages yet, so granted I
probably shouldn't be complaining. I know that with more experience in the
languages I'd probably get a better understanding of how they excel -- and,
unfortunately, where they don't.

Just... nothing seems to hit the sweet spot as well as Python and Javascript
has, for me. I guess that's an unrealistic expectation for not having actually
_worked with_ functional languages.

I want a functional language to _feel_ as smooth as Python. (If that just
requires more experience and familiarity, fine. But I'd be hard-pressed to
believe that the code demonstrated here could seem as clear to a Lisp expert
as Python equivalents would feel to a Python programmer.)

Are the issues Tim found in this post actually just caused by lack of
experience, or is this really how the language gets down to feel? I'd love to
hear what lisp (clojure or not) folks can share.

~~~
mreid
Haskell is the obvious alternative. It is a very elegant functional language
that is, in my opinion, executed well. Does it fit into your list of languages
that miss the mark. If so, in what ways?

I also really like Clojure at the moment but have programmed in Haskell in the
past and found there was much to recommend it. If you are genuinely looking
for a good functional language you would be doing yourself a disservice if you
didn't take a serious look at Haskell.

~~~
veemjeem
how is haskell the obvious choice? The parent poster talks about clojure &
python -- 2 dynamically typed languages. It's going to be a world of
difference moving to a statically typed one.

~~~
mreid
The change in typing is not really much of a jump when you realise that
Haskell's type inference means you don't have to declare too many type
signatures up front. A lot of type signatures in Haskell code are not
technically necessary and are usual there for documentation.

For example, this is perfectly valid Haskell code and doesn't mention a single
type:

    
    
        factorial n = if n > 0 then n * factorial (n-1) else 1
    

The bigger conceptual shift will be from Python's mainly procedural style to
Haskell's (or Clojure's) very strong emphasis on a functional style.

------
jimbokun
I'm really enjoying this series. Definitely getting down and gritty with what
Clojure is really capable of (and all the other languages he's tried). Of all
the articles I've read on concurrent programming and the languages that
promise new ways to handle it, I find the Wide Finder series the most
pragmatic and concrete.

~~~
swannodette
I wouldn't say that the article gets down to the nitty gritty of what Clojure
is capable at all. It's a great series about a high profile hacker having a go
at what I think is a great new programming language.

For a down and gritty analysis of Clojure optimization you're better served
reading Christophe Grand's posts. Or even my own fast but butt ugly
optimization of Uncle Bob's Jarvis March-
[http://github.com/swannodette/convex-
hull/blob/master/convex...](http://github.com/swannodette/convex-
hull/blob/master/convex_hull.clj) where I use macros to inline everything.

His version ran in 25s, mine in about 0.5.

------
icey
I'd really like to see a Common Lisp solution to the wide finder sometime (in
case any lisper is really bored and feels like cranking one out :D )

------
anonjon
I am shaking my head in dismay.

Reduce is a loop. Rewriting all of your loop code as reduce won't get you any
performance gains. If anything you will lose performance over looping because
you are now passing stuff to a function and it is getting boxed.

Why is he splitting all of the lines with a #"\n" regex? there are perfectly
good methods for reading something line-by-line in a number of places (in both
java and clojure).

I like Tim Bray and anyone who writes about clojure or lisp, but I feel like
I'm tripping on acid here.

~~~
runevault
Reduce is actually faster than using loop/recur normally IME. Probably at
least in part due to chuncked seqs which map and reduce among other functions
can take advantage of.

Most of the built in clojure functions are better optimized than doing things
by hand yourself.

~~~
anonjon
Reduce /IS/ a loop: (from clojure.core)

([f val coll] (let [s (seq coll)] (if s (if (chunked-seq? s) (recur f (.reduce
(chunk-first s) f val) (chunk-next s)) (recur f (f val (first s)) (next s)))
val)))

It follows that I can use chunks in a loop... chunking and looping are not
mutually exclusive.

It also happens to be the case that reduce is a function call, and (AFAIK)
that you can't use transients (like conj!) or make use of unboxed values.

This is an issue, as such, one should still loop for best performance.

~~~
swannodette
If I'm not mistaken chunking is only supported on some of Clojure's data
structures. Reduce is certainly the better option with vectors (and maps?) if
you write your own loop/recur you'll simply be duplicating the existing
implementation.

Also I really can't imagine using loop/recur on anything except for vectors
and maps most of the time anyway, so why not just use reduce?

