Archive for the ‘java’ Category

Don’t Do This

Tuesday, December 22nd, 2009
Tabs and spaces... mixed! The horror!

It’s like this in a lot of places throughout the project. :(

Does This Seem Strange To Anybody Else?

Wednesday, February 11th, 2009

It’s sort of a basic Java thing, but I think this seems counter-intuitive:

public class SomeClass {
 
    class InnerClass {
        private int privateInt = 0;
    }
 
    public void someMethod() {
        InnerClass innerClass = new InnerClass();  
 
        innerClass.privateInt = 1; // <-- this is legal        
    }
 
}

In the words of Firefly’s Jubal Early… does that seem right to you?

Java Generics: Too Much Work For Too Little Type Safety?

Thursday, March 22nd, 2007

As of Java 5, the Java language includes generics support.

This (long overdue?) feature lets you “generify” classes and methods to work on varieties of object types, while still maintaining some level of type safety.

Use of generics can be seen all over the place in the Java Collections library. Want a list of Strings? Declare:

List<String>

Want to map an integer id to a name? Say:

Map<Integer, String>

Sounds good? Let’s do a little experimenting with the way the system works.

Let’s say you want to write a class that represents a directed graph. (’Graph” here in the graph theory sense). So, you’ll want a class that contains a collection of vertex items along with a collection of edge items; each edge connects two vertices.

The Graph class will be responsible for creating the graph structure, but users of the class can make graphs out of anything they want. For example, you could make an interstate diagram with vertices of City objects and edges of Highway objects. Or, someone may make an Automaton class that contains a Graph with vertices made out of States, and edges made out of Transitions.

The natural thing to do is make Graph generic, and take in two type parameters; one for the ‘vertex’ type, and one for the ‘edge’ type. Then, your class may be used thusly:

Graph<City,Highway> interstateMap

or

new Graph<State,Transition>()

Great. So, let’s say you’ve started using this Graph class, and you have a bunch of Graphs with VType and EType for the vertex type and edge type, respectively. Now, you want to write a method that does something to Graph<VType, EType>s. So, you create a method with a signature something like:

public void doSomething(Graph<VType, EType> graph)

But wait. You also have classes that extend VType and EType, and you want your method to work on Graphs of those, too. Calling doSomething with a Graph<VTypeExtention, ETypeExtention> isn’t allowed unless you change your method signature to:

public void doSomething(Graph<? extends VType, ? extends EType> graph)

This is starting to get ugly. But, at least we’re sure to be type-safe, right?

But watch what’s legal to do inside of this method:

public void doSomething(Graph<? extends VType, ? extends EType> graph){
        Graph graph2 = graph;
        graph2.addVertex(new Foo());
}

So for all that overhead to make sure the Graph had the right type parameters, it’s that easy to add a vertex with the wrong type.

And what’s really bad is that not only will this code make it past the compiler, but you won’t even get a runtime exception when you call addVertex. The exception will come when you try to access the Foo item and call VType methods on it. It could be much later and at an unrelated place in the execution of the program.

You can’t even do the dynamic check manually, since type parameters aren’t allowed to participate in instanceof statements.

This is all caused by the erasure system Java uses to deal with Generics. The compiler makes static checks against the type parameters, then erases the type parameter information, then generates the byte code. At runtime,

Graph<? extends VType, ? extends EType> graph

turns into

Graph graph

and any dynamic type checking is out the window.

As far as guaranteed type safety goes, you might as well have made Graph with collections of plain old Objects.

I’m sure the erasure system is in place for many good reasons (backward compatibility among them). But, at the end of the day, issues like this make me feel like Java generics generate a pile of busywork for the programmer, but fail to truly pay off.