top | item 881642

Python vs Clojure

43 points| fogus | 16 years ago |blog.bestinclass.dk | reply

48 comments

order
[+] req2|16 years ago|reply
As with most language comparisons, the author is clearly established on one side of the fence and unwilling to investigate in any meaningful sense.

He begins with a somewhat spurious statement on how code must be arranged, continues with a complete misunderstanding of what most people mean by scope, and then accuses Python of innumerable memory leaks and associated bugs before he even gets through his first set of comparisons. He claims Python dictionaries abuse the term 'immutable', but they most decidedly never make any such claim. You might learn something about Clojure, but take everything he says about Python with a grain of salt.

(Anyone who is interested in concurrent Python should check out multiprocessing, not threading.)

[+] johnfn|16 years ago|reply
What bugs me about this article is that the solutions he takes for project euler are taken from a website which tries to make Python into a functional language and are needlessly verbose. For instance, the normal way to solve PE#1 is:

print sum([x for x in range(1001) if x%3==0 and x%5==0)]

Quite a bit shorter than the clojure solution.

Further, their "isPalindrome" function involves a "digits_from_num" call, and is almost 10 lines in total. You could shorten that to one if you check pal == pal[::-1].

Essentially, the guy copied code from a website which wasn't really trying to show off how succinct python could be.

[+] jongraehl|16 years ago|reply
TypeError: 'int' object is unsubscriptable

You have to use str(pal) first, I guess.

Your core point is right, though; his clojure uses number->string + reverse, and the Python can too.

[+] jbellis|16 years ago|reply
or perhaps more readably, pal == str(reversed(pal))
[+] jacquesm|16 years ago|reply
The author seems to be strongly biased against python.

I'm no great fan of some of pythons choices but I think if you find x things wrong with python and 0 wrong with clojure that that is fairly indicative that this is not a balanced review.

Which is a pity.

[+] gaius|16 years ago|reply
Not only that, he's wrong - Python is sensitive to indentation, not whitespace. As long as your block is at the right depth, you can have as much whitespace as you want. I regularly format code so similar things line up. This is perfectly valid Python:

    def foo():
        longvariable = 1
        x            = 2

Also on the subject of lambdas, this is also valid:

    def foo():
       def bar(x):
           return x + 5

        print bar(5)

With a nice clean syntax for nested functions, lack of multi line lambdas is much less of an issue.
[+] hendler|16 years ago|reply
From the blog - "I'm a professional freelancer working exclusively in Clojure."
[+] jongraehl|16 years ago|reply
He did the same sort of hatchet job on Scala a month ago.
[+] clemesha|16 years ago|reply
Every time I hear criticism of Python's whitespace (indentation), I am reminded once again of how much I appreciate and enjoy it.
[+] jacquesm|16 years ago|reply
To me it's a mixed bag. It's like a 'price of admission', if you've been conditioned a life long to look for matching braces (or at least begin, end pairs), and if even languages that are strictly speaking markup languages seem to feel the need for delimiting the end of a block in some way you alienate a large number of people before they've even written a single line.

Compound that with the difficulty of passing code snippets using various media and it is easy to see why so many people argue against this.

You can get used to it, sure. But that's not a very strong argument. I think there would have been ways to get out of this.

Especially when programming using tabs you'd better be very careful not to hit a delete by accident while walking near the end of a block of code. That can really mess you up.

edit: also, for that reason alone any discussion about the relative merits of python vs something else first has to get pas the 45% where we talk about the whitespace. And some people will go to extreme lengths to prove its 'goodness' even when clearly it is not only good.

Being objective about something you like is very very hard.

[+] bretthoerner|16 years ago|reply
I posted this there, but I feel more people prefer to read comments here.

---

First, I love both Python and Clojure, and completely agree that Clojure is more functional and aimed towards concurrency (this was its goal, after all). But I feel like you're doing Python wrong here.

> I think this should make a Pythonist a little jealous

No, I think you misunderstood the whitespace rules for Python. First, it isn't set to "4 spaces", it just has to be uniform. You could use 8 tabs if you wanted, or 2 spaces, or 7 spaces. Also, inside of data structures, strings, function calls, etc you can go whitespace crazy. This is valid Python:

    users = (# name ,      id,    age,     phone
             ("Frank",     200,    22,     "555-1234"),
             ("Johnathan", 201,    24,     "555-3213"),
             ("Peter ",    202,   101,     "555-2312"))
> The last print statement outputs "10" which is surprising to me, since y has never been declared in that given scope.

But it wasn't declared in that scope, there is no scope for 'if'. It may not be what you're used to but you can't blame Python for your assumption of what should have it's own scope or not.

> To resolve it you have to manually call 'del y'

What do you mean to resolve it? Why are you deleting the reference at all? You very rarely see 'del' in real Python code.

> but I can't count the number of C app's that have suffered from memory-leaks and what not, based on the lack of automated garbage collection

What does that have to do with Python? It is reference counted, those values will be deleted when they go out of all scopes, just like in Clojure.

> But this is very different from Clojures concept where immutable means: 'x' never changes.

That isn't what it means in Clojure at all.

    user=> (def x 1)
    #'user/x
    user=> x
    1
    user=> (def x 5)
    #'user/x
    user=> x
    5
I just changed 'x'. What immutability means is that the value 'x' points to does not change. And that's exactly what it means in Python, too, but dictionaries are mutable (and this is documented). For example, strings in Python are immutable, just as in Clojure. If two things reference the same string and one "changes" it only means that it references a wholly new string.

> Guido is not preparing to transition into modern programming

That's a little extreme. Concurrent programming is valuable, but there will also be many programs that fit single process / thread models very well until the end of time.

[+] mr_dbr|16 years ago|reply
The whole sentence regarding an if blocks (lack of) scope seems.. wrong.

> .. since y has never been declared in that given scope. I don't quite know how Pythonists handle this, but I can imagine many situations where this will be the cause of much confusion

Given the following code:

    if some_irrelevant_function():
        x = 2
    else:
        x = 5

    print x
The author is claiming it would be less surprising for that to raise a NameError exception, complaining x is undefined?

> To resolve it you have to manually call 'del y'

No. You just have to be sane with the usage of your variables. I have never run into a situation where this has been a problem.

> I don't have the numbers for Python, but I can't count the number of C app's that have suffered from memory-leaks and what not, based on the lack of automated garbage collection. With Pythons use of scope, I imagine quite a few bugs will follow.

Err, no.

----

> Now in one Python doc I found they actually refer to this type of data [dictionary] as immutable

Assuming the docs actually say this, they are incorrect and should be amended.. Dictionaries are absolutely mutable.

> Lambda

Err. The complaint here is you cannot use "?" in an identifier...?

> To Pythons credit it actually pinpointed the exact character which caused the exception - You shouldn't except that much help from Clojures backtraces....yet

Not to make this into a "languageX vs languageY" debate, but I'd say having decent error messages is far preferable to being able to use symbols in an identifiers name..

[+] dreish|16 years ago|reply
I agree for the most part, but incidentally you would never (def x 1) and then (def x 5) in a running program -- you would use an atom, ref, or var instead. Redefinition of a symbol is permitted so you don't have to quit and restart your REPL every time you rewrite a function.

A more meaningful objection is that you can shadow a local with a different local in Clojure, like this:

  (let [a (some-calculation)
        b (something-else)
        a (some-function-of a b)]
    a)
which is essentially what is being done in the Python code.

I don't think there are many strong arguments to make in favor of Clojure over Python other than concurrency and macros, and maybe the immutable hashes.

[+] tetha|16 years ago|reply
Regarding concurrency: check out multiprocessing. Very, very simple access to process concurrency to do things.
[+] icey|16 years ago|reply
I like Clojure, but this whole article strikes me as thinly veiled language trolling. It's not a comparison, it's a long blog posting talking about how Lau thinks Clojure is better than Python.
[+] jacquesm|16 years ago|reply
What's veiled about it ?
[+] megaman821|16 years ago|reply
This comparison isn't very good.

He is basically dinging Python for setting up some pretty basic functions like ireduce(). Wouldn't you do the same in Clojure if something didn't exist? If its just about have short code, I would suggest the line 'import numpy'.

Also for the concurrency parts, if you are talking strictly about the languages and not their implementation, why not compare Jython to Clojure?

[+] jacquesm|16 years ago|reply
Because then the comparison would come out less in favour of clojure ?

Because the author isn't aware of jython ?

It could be anything really, but if you plan on putting down a language I guess you're not going to go out of your way to create a level playingfield.

Let's compare interpreted basic with compiled C for an encore.

[+] jbellis|16 years ago|reply
> He is basically dinging Python for setting up some pretty basic functions like ireduce()

I don't get it. plain "reduce" already works on any iterable.

[+] pHezy|16 years ago|reply
It seems more like a "I suck at python and I try to be cool using clojure" than any other things. Oh, and btw, palindrome: x==x[::-1] or reversed
[+] kljensen|16 years ago|reply
Clojure seems super cool. But, 99% of my tasks - are simple & easily accomplished in Python; and - do not require any concurrency.

It seems like Clojure would be super useful in number crunching like scientific computing, etc.

[+] alrex021|16 years ago|reply
Who is up-voting this?

If you read this article you can clearly see the lack of knowledge the author holds in Python language itself. If you gonna do a ... VS ... you better know both sides pretty damn well otherwise it leads to being a somewhat worthless comparison IMHO.

[+] japherwocky|16 years ago|reply
tl;dr: author without much python experience writes a tedious article in Clojure's favor.
[+] d0mine|16 years ago|reply
There is a bug in the fibonacci example: it sums odd numbers instead of even.

  from itertools import takewhile
  
  def ifibonacci(a=1, b=1):
      while True:
          yield a
          a, b = b, a + b
  
  candidates = takewhile(lambda n: n < 4000000, ifibonacci())        
  print sum(n for n in candidates if n % 2 == 0)