CICE: Not So Nice
I’m still trying to wrap my head around closures, so I can decide if they’re a good idea or not; but there is one specific proposal I am willing to shoot down: Concise Instance Creation Expressions by Bob Lee, Doug Lea, and Josh Bloch. In fact, I think they shoot it down themselves pretty effectively without noticing what they’ve done. Here are their examples:
For example, here is the Java 5 code to start a thread whose run method
invokes a method named foo:new Thread(new Runnable() { public void run() { foo(); } }).start();
If we adopt this proposal, the following code would be equivalent:
new Thread(Runnable(){ foo(); }).start();
Here is the Java 5 code to sort a list of strings by length (from shortest to
longest):List<String>ls = ... ; Collections.sort(ls, new Comparator<String>() { public int compare(String s1, String s2) {< return s1.length() - s2.length(); } }); Here is the same code rewritten using the proposed syntax:
List<String>
ls = ... ; Collections.sort(ls,
Comparator<String>(String s1, String s2){ return s1.length() - s2.length(); });
Which is more legible to you? To me, the answer’s obvious: the anonymous inner class version that’s nicely indented. It’s not an ideal solution, but it’s better than the CICE alternative. The CICE alternative is a confusing mishmash of brackets, braces, and parentheses. Frankly, it’s starting to look like Perl. It’s shorter than the traditional approach, but that’s not a good thing. The redundancy and white space of the current syntax helps us read it, understand what’s going on, and makes it more legible. The compiler doesn’t need it, but we humans do. The CICE proposal lets the compiler fill in too much. The more that is implied by the code, the more the compiler fills in, the harder the code becomes to understand. Indeed the only way to explain or teach this stuff is to rewrite the example using traditional syntax, and tell students what’s the compiler is really doing is that.
We’ve already seen the confusion caused by the compiler writing code for us. Since Java 1.0, the compiler has helpfully filled in default constructors and default calls to super()
, and this is a much simpler case. That’s probably a net benefit, but barely at best. Problems with default constructors trip up almost every student learning Java eventually; often more than once. Explicit code is good. Implicit code is bad. Explicit code you can read. Implicit code you have to remember. Reading is easy. Remembering is hard.
The second thing I don’t like about CICE is that it proposes a lot of weird rules about defaults. For instance, sometimes local variables will be final by default and sometimes they won’t. They’ll be final if they can be; that is if nothing assigns to them more than once. Then they can be used inside this new CICE expression. Otherwise they won’t be. However that’s going to cause massive debugging pain. Everything will be working fine, and then you add a simple statement like x = x*2;
and suddenly the compiler starts spewing weird error messages that have nothing obvious to do with what you changed. I’m sure Bloch and Lea can figure this out in two minutes when it happens to them. I’m equally sure that my students and other not-as-expert programmers are going to waste many hours on this problem.
Why I Don’t Like Anonymous Inner Classes
It’s worth noting that my objections are grounded a little further back. I don’t really like anonymous inner classes all that much, and frankly I’m not that fond of regular inner classes either. They’re a constant source of annoyance because they never work quite like I expect due to all those silly rules about final local variables, this
inside inner classes, and other arcana I can never quite remember. At this point I’ve given up on getting it right the first time. I just write the code I want to write, then debug the inevitable compiler error messages. I’ve gotten pretty good at that, but it’s still an annoyance.
When I teach Java, I tell my students not use inner classes of any kind; and indeed I forbid them from doing so on some of their homeworks. I find that if I let them use inner classes they just become a crutch to replace global variables. The students never learn how to use methods to pass information and commands back and forth between objects. They just touch all the private parts directly, and they don’t know or care that behind the scenes the compiler is generating getters and setters. I do teach them what inner classes and anonymous inner classes look like, because they’ll have to read code other people have written using inner classes. However I recommend that they don’t use them themselves.
CICE is going the wrong way. Rather than removing the things that cause the confusion (inner classes) it’s adding more of them, and worse yet hiding them under the carpet where only the compiler sees them. I want code that’s more explicit and obvious, not less.
CICE is not syntax sugar. CICE is syntax cayenne pepper. It takes one of the ugly, confusing (and unnecessary) parts of the Java language and makes it even uglier and more confusing. Possibly real closures might be better, and might indeed remove a lot of the ugliness that is inner classes. However CICE doesn’t do that. CICE makes matters worse, not better.
February 1st, 2007 at 9:04 am
[…] I was debugging some problems quoting a piece of a Google Doc article when I noticed something funny in their HTML source, an apparent string bogon. For example: […]
February 1st, 2007 at 9:59 am
> Which is more legible to you?
The one liner is infinitely more readable to me. Running away from a language’s capabilities because they’re “hard to remember” is silly.
> I tell my students not use inner classes of any kind
Wouldn’t it make more sense to teach them how to use inner classes correctly? And anonymous classes too? Swing is littered with anon classes and is a great example of how to use them effectively.
February 1st, 2007 at 10:24 am
Teaching the proper use of anonymous inner classes requires first teaching the proper use of regular classes. If you let students use anonymous inner classes or even named inner classes before they’ve gotten good with classes, they will use them wrong. I guarantee it. (I am assuming the students are not truly familiar with OOP from other languages first. You could teach people who already knew C++ or C# or Eiffel well very differently, but that’s not most of the people I teach. These days most students’ first course in Java is likely to be their first exposure to OOP.)
In one semester, students don’t have time to learn both. Once students are finally comfortable with regular classes, anonymous inner classes are a small bit of syntax sugar, but they’re not necessary, important, or all that useful. It’s trivial and mechanical to replace an inner class with an outer class. The ability to do so is a good indicator of whether someone really understands OOP. Hmm, it occurs to me that would make a very nice final exam problem. I’ll have to remember that come May. 🙂
February 1st, 2007 at 11:18 am
Dissing inner classes. I don’t know; is that enough to get tossed out of The Brotherhood? Niemeyer doesn’t like them either. Maybe it’s an O’Reilly fetish? But I do agree. Since they’re just compiler foolery, best to avoid them.
February 1st, 2007 at 12:22 pm
“Which is more legible to you?”
The CICE one, after it’s properly indented. Nobody forces you to use the unindented version.
“all those silly rules about final local variables, this inside inner classes, and other arcana I can never quite remember…”
You do understand all those silly rules exist _because inner classes are not closures_, right? If Java had real closures, they would go away.
See http://gafter.blogspot.com/2007/01/definition-of-closures.html.
February 1st, 2007 at 1:03 pm
I don’t think CICE is the best solution to the problem that inner classes are trying to solve. In the case of sorting, closures are extremely intuitive. I don’t know what the proposed syntaxes for closures in Java look like, but here’s what sorting a list of strings may look like with closures:
List ls = …
ls.sort(s1, s2) { return s1.length() – s2.length(); }
This is not only shorter, but it’s also much more intuitive.
February 2nd, 2007 at 4:36 am
I totally agree that this proposal adds complexity to the language with no real benefit in return; it’s totally the wrong direction. We should be trying to smooth out the rough edges of Java rather than add obscure special cases of syntax. Unfortunately while auto-boxing and generics could have increaced the clarity of Java, their implementation introduced more complexity and gotchas. That’s exactly what we should be trying to avoid with any new language feature.
February 4th, 2007 at 9:42 am
In the Runnable examples, how does it know you want to invoke run()? Does it just infer that because it’s the only method and has no args?
February 4th, 2007 at 8:34 pm
I think the CICE proposal is better than the BGGA proposal because it uses an inner class which is more powerful than a simple closure and also already in Java. I have also suggested another alternative syntax for inner classes, C3S (http://www.artima.com/forums/flat.jsp?forum=106&thread=182412), which I think is more Java like than either. Taking the sort example given in the original post above but indenting:
In CICE:
List ls = … ;
Collections.sort(
ls,
Comparator( String s1, String s2 ) { return s1.length() – s2.length(); }
);
In BGGA (I think – you need a closure conversion to make a closure into an instance of an interface – which I think is intended to be implicit):
List ls = … ;
Collections.sort(
ls,
{ String s1, String s2 => s1.length() – s2.length(); }
);
Note the use of => to separate arguments from body and that you can’t use return in this context, the value returned is implicitly the value of the last statement and if you add an explicit return it is an error.
In my C3S proposal:
declare ls = … ; // Note type inference from right hand side of equals sign
Collections.sort(
ls,
method( s1, s2 ) { return s1.length – s2.length }
);
I find this C3S more readable than current Java, CICE, and in particular BGGA. What do others think?
February 6th, 2007 at 2:11 pm
Ugh. Who let the bazaar into the cathedral?
If the future of open source java is scratching everyone’s minor itch to “fix” the language, maybe it’s finally time to move on to python or ruby.
February 8th, 2007 at 12:19 am
If you find the CICE unreadable, may the force be with you to help you decipher the BGGA proposal.
July 12th, 2007 at 7:02 am
[…] Harold has been vocal against adding complexity to the Java language. The complexity loving geek in my stamps his foot […]
December 20th, 2007 at 7:38 am
I think you are missing the point.
The whole idea about having closures is just having a way to pass a Java block as a variable. We already do that using Runnable, but the whole point of Runnable is that it is an anonymous inner class and half the code you type is just boilerplate.
Can we remove the bolierplate?
If the answer is yes, then we don’t need to introduce new mechanisms into Java. That should be one of the deciding criteria.
The example should be about moving the block into a variable. Also you are not instantiating a class, but a block (which is finally a method, and it doesn’t matter if internally Java uses the anonymous inner class mechanism):
int compare( String, String ) = Comparator.compare( String s1, String s2 ) { return s1.length() – s2.length(); };
Collections.sort( ls compare );
It has better syntax, doesn’t it?