Saturday, May 26, 2007

As a language grows by the addition
of
features, it necessarily gets more complex. After all, you can't remove
existing language features because existing programs use those
features, but each additional feature adds complexity. Right?

Fellow Googler Matt Shulman asked me a question about the Closures for Java
specification. He observed that much of the complexity arises
because of support for checked exceptions in the spec. Things like throws
type parameters, disjunctive types, and throws clauses on function
interfaces would be unnecessary without checked exceptions. Matt asked
me if we had considered if things would be simpler without all that. At
first I misunderstood his question to be referring to just the Closures
specification, so I answered that the facility wouldn't fit
into the language as well without support for checked exceptions.

Matt clarified that he was asking not just about removing
support for checked exceptions from the Closures spec, but from the
entire programming language.

There has been an
ongoingdebate
on the utility
of checked exceptions. Many people are critical of Java's
checked exceptions, characterizing them as a failed experiment in
software engineering. In practice, checked exceptions can result in API
complexity, and programs appear to be cluttered with
exception handling code just to satisfy the compiler. Some people
believe checked exceptions are a good language
feature but are misused,
even in the JDK. With the "experts" being such poor role
models, how can we expect ordinary Java programmers to do better?

We did
a Google
search to see how many people have written in support of
checked exceptions and how many people don't like them. The discussion
seems to be lopsided against checked exceptions, but on the other hand
that may be due to the fact that checked exceptions are the status
quo.

This isn't a question I had thought much about. I believe the
language could be simplified by treating all exception
types as unchecked without breaking existing programs. This could also
result in a simplification of future language extensions and APIs. But
would the language and platform be better off without checked
exceptions?

Sunday, May 20, 2007

Watching Josh Bloch's presentation at JavaOne about new topics
in the second edition of Effective Java
makes me want to go out and get my own copy. Unfortunately, he's not
scheduled to have the new edition in print until later this year.

There was a coincidental adjacency between two slides in
Josh's
talk that made me think a bit more about the idea of Super Type Tokens.
The last slide of his discussion of generics gave a complete
implementation of the mind-expanding Typesafe Heterogenous Containers
(THC) pattern using Super Type Tokens:

But on the very next slide, the very first bullet of the
summary of his presentation reminds us

Don't ignore compiler warnings.

This was referring to Josh's advice earlier in the
presentation not
to ignore or suppress unchecked compiler warnings without trying to
understand them. Ideally, you should only suppress these warnings when
you have good reason to believe that the code is type-safe, even though
you might not be able to convince the compiler of that fact.

The method Favorites2.getFavorite,
above, is annotated
to suppress a warning from the compiler. Without that annotation, the
compiler complains about the cast to the type T, a type parameter. Is
this code demonstrably type safe? Is it possible to cause this cast to
fail using code that is otherwise completely type safe? Unfortunately,
the cast is not safe:

This program compiles without warning, but it exposes the
loopole in the type system created by the cast to T in Favorites2.getFavorite.
The compiler's warning does, after all, tell us about a weakness in the
type safety of the program.

The issue is a subtle one: TypeRef
treats two types as the same when the underlying java.lang.reflect.Type
objects are equal. A given java.lang.reflect.Type
object represents a particular static
type appearing in the source, but if it is a type variable it can
represent a different dynamic
type from
one point in the program's execution to another. The program Oops
exploits that mismatch.

The Super Type Token pattern can be redeemed by disallowing
the use of type variables anywhere in the Type object it stores. That
can be enforced at runtime (but not at compile time) in the constructor.

About Me

Neal Gafter is a Computer Programming Language Designer, Amateur Scientist and Philosopher.
He works for Microsoft on the evolution of the .NET platform languages.
He also has been known to Kibbitz on the evolution of the Java language.
Neal was granted an OpenJDK Community Innovators' Challenge award for his design and
implementation of lambda expressions for Java.
He was previously a software engineer at Google working on Google Calendar, and a senior staff engineer at Sun Microsystems,
where he co-designed and implemented the Java language features in releases 1.4 through 5.0. Neal is coauthor of
Java Puzzlers: Traps, Pitfalls, and Corner Cases (Addison Wesley, 2005). He was a member of the C++ Standards
Committee and led the development of C and C++ compilers at Sun Microsystems, Microtec Research, and Texas Instruments.
He holds a Ph.D. in computer science from the University of Rochester.