Java.next() - Clojure: The Return of the Lispers
batsov.com
batsov.com
public boolean hasUpperCase(String word) {
if (word == null) {
return false;
}
int len = word.length();
for (int i = 0; i < len; i++) {
if (Character.isUpperCase(word.charAt(i))) {
return true;
}
}
return false;
}
Where it should be this: public boolean hasUpperCase(String word) {
return word != null && word.matches(".*[A-Z]+.*");
}
It casts doubt on the other examples. I'm not saying Java isn't a verbose language that can get tedious, but let's use some decent examples. (defn has-uppercase? [string]
(some #(Character/isUpperCase %) string))
This code can deal with any sequence of characters: String, Array, PersistentList, PersistentVector, Cons, LazySequence, etc. Your example only deals with String.That said, I'm really excited about Clojure. I got back into programming via Ruby and now Clojure is getting me back into data structures.
Nobody writes code to see if a string has an uppercase character, that code was written long ago. Regex may be something that Java imported, but it's right there in the JDK so I have no reason not to use it. How do the two languages look when you're validating email addresses against a whitelist of domains from a config file or URLs for parameters based on some business rules? How do you handle an I/O error when you're halway through writing a file? These are the small problems we know we'll have to do over and over again, but not be able to stash in a standard library (or use someone else's). Pointing out that JavaBeans are silly doesn't hold much weight either, I use lombok :)
I've seen MUCH better writing here on HN.
But hey, downvote away.
http://www.jarvana.com/jarvana/view/org/apache/axis2/axis2-k...
But i don't know whats less performant, your reimplementation with regexes or the clojure sample.
The Regex version, while similarly terse would be massively slower.
I agree the example is a bit odd, but it does serve the purpose of comparing equivalent code, which I believe is the whole point.
It does do the job of showing that simple (and by inference (?) not so simple) algorithms can be more succinctly expressed in Clojure than in Java. (not that that is particularly difficult)
> It does do the job of showing that simple (and by inference (?) not so simple)
> algorithms can be more succinctly expressed in Clojure than in Java. (not that
> that is particularly difficult)
My point was not that Java is/can be as concise as Clojure (or Ruby or Python or some other version of Java or whatever) but that if you are focusing on comparing things, don't use examples that are so easy to write off. It is not clear to me, as a person experienced with Java but not with Clojure, that the Clojure method deals with many types of character sequences, nor is it clear to me that it's faster or slower than a regex match. If the argument solely lies on lines of code, my mind will think "is he comparing code optimized for performance from one language to code optimized for conciceness from another?" Is that ability to traverse sequences some bona-fide intelligence on the languages part or just a mess of instanceof expressions that really only work for a few expressions?This just struck me because I've been evaluating a lot of languages lately (Clojure is up soon) and it's frustrating to wade through people talking about languages using examples that are ignorant of all but their own, or contrived solely to make a point. Demonstrate the language in how powerful it is, how efficiently it runs, how gracefully it handles errors, how many lines of code it takes to solve specific problems, not standard utility ones that could easily be tucked into some library somewhere and it doesn't really matter if its 2 lines or 20.
I don't know, that is a lot to ask. You yourself state that you can't understand this example in Clojure, which as you admit is almost trivially simple. Again, I'm 99% positive the Clojure as written is exactly equivalent to the full Java versions, so he really couldn't be clearer on this particular example.
It is a hard task in the end as an author, to come up with an example that CAN be understood by someone who likely only knows one of the languages talked about, yet still provide some comparison. I think he deserves some credit in that he does try to make them exactly the same code (probably very similar bytecode even), just expressed in that language.
To your contrived point, I would say running through the elements in a list and operating on them is far from contrived, rather it is one of the most common operations we do day to day. That Java is particularly verbose about that isn't the fault of Clojure.
To keep this constructive, what piece of Java code / functionality would you use as an example?
Running through elements in a list is obviously common, but that's not what was done here, he was checking for a particular validation that just so happens to have been easy in Clojure and messy in Java.
Here's an example that I think is a little more realistic, but not so complicated that it requires a lot of work. It doesn't use anything outside of the standard SDK, and yet it illustrates some i/o, data structures, error handling and return values, and useful logging, all in a pretty small amount of code that you could definitely see in a real project:
https://gist.github.com/975368
This is clearly not Java at it's best, the finally block shows how some basic scoping can get verbose, and the nested try/catch isn't great, but it's tough to improve it without refactoring some of the messy bits out, which would really only help with organization, not verbosity.
26 lines. I expect Clojure or most other languages to do it in fewer lines, but I'd be surprised if they can do it in half and still account for the requirements. My overall point here is that you could probably read a file into a list in some languages in a couple of lines, but when you start adding some reality in, they pack on some pounds.
If someone wants to prove me wrong, please do, you might have a convert :)
I do hope someone will post an equivalent Clojure program. Unfortunately, my knowledge of Java is limited, and I have not touched Clojure in many months now, so cannot do it myself. Sorry.
https://gist.github.com/976020
I think the biggest advantage of Clojure over Java for code like this is how easy it is to use lazy sequences and higher-order functions.
In this example there isn't much to be gained in the error-handling and logging; however, if there were other similar functions it might be easier to factor out some of the common patterns in Clojure, since functions like the predicate to ignore a line can be easily passed through. Or, for example, you could write a custom version of with-open or line-seq to do the desired logging behind-the-scenes.
Whether or not that is truly representative of java code is perhaps another question but there is certainly a body of similar accepted code out there eg http://commons.apache.org/lang/api-2.5/src-html/org/apache/c....
class Person {
String name;
int age;
Person(String name, int age) {this.name = name; this.age = age}
}
This is still more verbose than the (defrecord person [name age]) but still, I agree with the dodgy examples used.Disclaimer : I don't know Clojure or similar and therefore I could be missing something. I did a quick search for defining private attributes in Clojure but didn't find any good hits.
public boolean hasUpperCase(String word) {
if (word == null) {
return false;
}
int len = word.length();
for (int i = 0; i < len; i++) {
if (Character.isUpperCase(word.charAt(i))) {
return true;
}
}
return false;
}
or
public boolean hasUpperCase(String word) {
if (null != word)
return any(charactersOf(word), new Predicate() {
public boolean apply(Character c) {
return isUpperCase(c);
}
})
else
return false;
}I believe Kawa is also currently a bit friendlier on Android as Clojure has some overhead. (More at http://dev.clojure.org/display/design/Android+Support)