“Lisp and Java” by Dan Milstein is one of those articles which describes how useful first class functions are in a language which has them (Lisp), then attempts to implement an approximation to them in a language that does not have them (Java, in this case).
The one odd thing here is that Java already has first class functions through its reflection capabilities. But, as the article states, “The complexity of using reflection here is a clear demonstration of why it's too tricky to use in day-to-day programming.”
And check out the code sample that uses Java's reflection and true first class methods:
public class RFMaker implements RowFunc { private Constructor _cons; public RFMaker(Class c) { try { _cons = c.getConstructor(new Class [] { ResultSet.class }); } catch(NoSuchMethodException e) { throw new IllegalArgumentException( "RFMaker must be called with a class " + "which has a ResultSet constructor"); } } public Object of(ResultSet rs) throws SQLException { try { return _cons.newInstance(new Object[] { rs }); } catch(InstantiationException ie) { throw new RuntimeException( "RFMaker failed due to: " + ie); } catch(IllegalAccessException iae) { throw new RuntimeException( "RFMaker failed due to: " + iae); } catch(InvocationTargetException ite) { try { SQLException e = (SQLException) ite.getTargetException(); throw e; } catch(ClassCastException cce) { throw new RuntimeException( "RFMaker failed due to: " + ite); } } } }
Yikes. Compare to the conceptually equivalent lisp code:
(defun rf-maker (class) #'(lambda (rs) (make-instance class :result-set rs)))
(That may not quite be fair, since most of the difference in length between the two code samples is due to exception handling. But Java made its bed, and now it is lying in it--right here on lemonodor!)
As Gavin said, “This article is like getting over tickled: it starts to hurt, you panic, can't breath, etc.--started out fun but ended in misery. Java just can't help it.”
Posted by jjwiseman at March 30, 2004 10:48 AMhttp://www.ai.mit.edu/~gregs/ll1-discuss-archive-html/msg04045.html
"And you're right..."
Yes, but exception handling is a plus, not a negative. You seem to be comparing two functions, one of which is much more complete than the other, and then complaining that the more complete one takes up more code.
Also, the Java code has some mistakes - for example you don't need to catch a ClassCastException. You can either assume it's good, or use the instanceof operator to check before assuming anything.
Yes, as I mentioned, this is not a completely "fair" comparison, by which I really meant that you shouldn't infer too much from it.
The fact is, though, that differences between the languages do contribute to the differences in code length. The way I wrote it in Lisp probably is the way that most Lisp programmers would have written that code, and the way it's written in Java doesn't look obviously atypical to me as a one-time Java programmer (though it might be argued that anyone using reflection in Java is not exactly typical).
As far as exception handling goes, I'm not sure that the Java code does anything better than what the Lisp code is doing. The lisp code will throw exceptions if something goes wrong. The only difference is that the Java programmer has to make a choice between declaring that various exceptions may come out of a method, or catching them in the method. In this case, they chose to catch them in the method and turn them into new exceptions.
The Lisp code could do the same thing, but my intuition, and experience, tell me that most Lisp programmers would not explicitly handle the exceptions.
I don't believe that the Java code is more "complete" than the Lisp code. It is true that the Java programmer has chosen to do more work in processing exceptions, but (i) it's not clear to me that that extra work is necessarily beneficial, and (ii) I believe that the two pieces of code are written in styles typical of their respective languages. So in that sense, I think the comparison has some validity.
I suppose the difference in part comes down to what the langauges were designed to do. Java enforces a certain rigor in the code, at the expense of power. Lisp doesn't enforce much of anything, and is therefore much more powerful. But the reason why Java has succeeded is because the code you have to write is more thorough, in a way that compensates for the mistakes programmers tend to make.
I would agree that it doesn't really buy much for short informal programs, but for applications that have to be more robust, whether small utilities or enterprise applications, it does in fact pay off.
So is the Java code more complete? I would guess that depends on the context.
Suppose you have methods foo0() and fooN(). I think you'd agree it's desirable to be able to place intermediate methods in the call stack between the two, for abstraction.
The problem is that if fooN() has a certain exception in its signature, the intermediate functions can't handle it without breaking abstraction. You have three choices: a) have the intermediate functions throw Exception, b) write special versions of the intermediate functions which throw the specific exception fooN() throws, or c) fooN-1() handles the exception.
I think we all agree that abstraction is the way to overcome software complexity. Java breaks it, and is therefore unsuitable for large projects.
Maybe if Java got type inferencing... Or Java programmers can beg Sun to be more like C#, which fixes this.
Posted by: Tayssir John Gabbour on April 2, 2004 01:05 PMi like java , and are you all right
Posted by: yu chen on April 1, 2007 09:26 AM