Skip to content

Comment on What is Clojure good at?

Comments

Clojure is fine, but just to play devil's advocate:

First of all, the repl is a killer. This is not something that is unique to clojure, but that doesnt make it less good. Beeing able to try out new api’s and fumble forward is great.

You can do this with Java and every other language. There's even a C++ REPL floating around out there. The real difference between Clojure (and CL, and Haskell) is that there is a REPL culture -- library designers use a REPL, so using one to play with their library feels natural. Trying using a C++ or Java REPL and you'll find that... it's not so nice.

Second, there is no compile time. It is not that the compile time is short, it doesnt [sic] exist.

Not correct. Fast compile time is always nice, and it's great that you don't notice. But this statement is simply not technically correct.

Third, functions without state and side effects are alot [sic] easier to test then [sic] java code. Yes you can still create hard to test code, but it is harder.

But of course, nothing in Java forces you to use state and side effects. It's a culture problem, again; but if you use Java libraries from within Clojure, you are going to run into those same culture problems.

Fourth, you can abstract away more code.

This is true. Java is missing something like Perl's "roles" that allow you to have code in interfaces. Imagine an "Equal" interface that defines equals and not equals. In Perl, you can provide a default implementation for not equals in terms of equals in Equals. In Java, well, I hope you like cut-n-paste or messy delegation. (I have never seen a Java programmer do this, but here's the pattern. Create a NotEquals class that has one parameter, a class that does the Equals interface. Implement not equals by delegating to equals in the object that was passed in. Now you have a class that can do equals and not equals; so create an instance and delegate YourClass.not_equals to NotEquals.not_equals. Now you can get not_equals without cut-n-paste. This is too hard for most people to figure out, it seems.)

With a higher-level syntax, you can add Roles later, or automate the delegation, so you can pick which design to use based on which one makes the most sense, instead of which one means you have less boilerplate to cut-n-paste. And that's the joy of high-level languages; you can write good code without wearing out your fingers.

But of course, nothing in Java forces you to use state and side effects.

Just because you aren't forced doesn't mean the language doesn't encourage particular styles based on the tools available.

If a library is designed with the "create object, set initial properties, call methods that alter the properties, retrieve the new properties" paradigm in mind where everything has its own custom structure, then wrapping the whole process in a function that returns standard abstract data structures (lists, hashes, sets) is going to be extra work. Valuable work, perhaps, but many programmers are not going to bother. On the other hand, if the library is designed with "pass arguments, return abstract data structure" then writing other functions in a similar manner will be natural.

But of course, nothing in Java forces you to use state and side effects. It's a culture problem, again; but if you use Java libraries from within Clojure, you are going to run into those same culture problems.

This is a known problem. There is an in development feature called Pods that will allow you to use nasty mutable Java libraries as well write your own nasty Clojure mutable code (perhaps for performance reasons) w/o destroying concurrency guarantees. I'm looking forward to see how it shakes out.

> w/o destroying concurrency guarantees

Pods will provide more than that since you can provide concurrency guarantees with locks only. However, Pods should additionally help with:

1. Separation of mutation logic and value policy with the Pod handling the underlying juggling 2. Lock order acquisition guarantees

There is more to it than this, but stay tuned for Rich's upcoming talk at the Clojure Conj. :-)

I meant to write "w/o destroying concurrency guarantees and w/o adding undue complexity". With Pods you don't need explicit locking from what I understand, right?

> With Pods you don't need explicit locking from what I understand, right?

That is my understanding yes.

Now I am beginning to understand why people like Clojure so much. Instead of calling them "state threads", whose Google results turn up academic papers from the early 90s, they call them "pods", whose Google results have nothing to do with programming.

Having a short name for commonly used structures aids readability. e.g.

    (ref {})
    (atom [])
Instead of:
    (software-transactional-memory-reference {})
    (atomically-mutable-reference [])

I can't really tell if you're being sarcastic or not

In one company, where Scala is used, they decided to refer to Monads as "comprehensibles" (due to Scala's "for comprehensions", which can be used like Haskell's do statement) in their standard library and documentation: lets everybody use Monads without the knee-jerk reaction of "isn't it some esoteric category thing that Haskell people have to use to do I/O".

There is not really alot of documentation yet so you want find any even if you tree more words.

> This is true. Java is missing something like Perl's "roles" that allow you to have code in interfaces. Imagine an "Equal" interface that defines equals and not equals. In Perl, you can provide a default implementation for not equals in terms of equals in Equals. In Java, well, I hope you like cut-n-paste or messy delegation

Scala has this feature too, as "traits". Under the cover, it does exactly what you describe with the JVM bytecode.

Of course, you can "achieve" the same feature with IntelliJ Code->Generate>Generate Delegators. You can use Yasnippets with emacs to do this and I am sure Eclipse has this feature too. While using an IDE can save the tedium of cut and paste ), it can't save the tedium of reading this code and understanding what it does (especially if you're manually mixing in multiple traits this ways).

Many good Java people are very receptive to Scala, but some tell me "my IDE can generate this, why do I need it?". They miss the point of abstraction.

Of course, that doesn't even cover abstractions that the IDE doesn't have: like pattern matching, or typeclass like abstractions with implicits, optional lazy evaluation (you can make a class called "public class LazyRef<T> { T force() { ... }}", but this is something your IDE doesn't have a "refactor button for").

Java's community has been to codify abstractions not present in Java using "design patterns" e.g., visitor pattern for multiple dispatch, delegates for traits/MI. Of course, if you want these features now you can just use other JVM languages (Clojure for MD, Scala for traits). What's interesting is that Microsoft/.NET team has been integrating these features into their "blub for the masses" (C#) e.g., Monads in LINQ despite also support distinctively non-blub languages (F#, funding Scala on the CLR).

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.