Java rant | > Techblog
|
Well Sun is surely going to release the final version of java 1.5 "tiger" quite soon. The new features are really just syntax sugar apart from two more important ones:
The correct response would be exactly the opposite - if I had it my way the entire class library would be written in C or C++.
The argument for making more and more code be "pure" java code stems from the inefficiency of calling native code from java code and vice versa. From that point of view it makes some sense that if you can have a completely java system, you get a performance benefit.
The fallacy is two-fold. Firstly, if calling native code from java code is inefficient, then that needs to be addressed urgently. Look at gcc's efforts with this; their "CNI" is much more efficient than the JNI (java native interface). But even GNU classpath seems to have fallen into the trap of thinking that java code is better than native code, sadly. For Sun's VM, the real problem - an inefficient inter-language communication mechanism - has not been addressed.
Secondly, java code is (to some degree) naturally inefficient and will always be so. Granted, techniques such as just-in-time compiling can really level the playing field in terms of speed - in some cases - but in terms of memory usage natively compiled stuff is pretty much always going to win out here. There's a lot of overhead in java classes. Increasing the amount of java code in the system is just increasing the overall bloat and overhead of the VM.
It's all very well that some of that bloat is now shared between different processes, and certainly that must be quite an improvement, but the bloat factor is still there.
And now, java has them! Which is fantastic. The implementation is pretty clever too, it avoids introducing unnecessary overhead or heavily modifiying the underlying virtual machine.
It's true that reflection doesn't work particularly well with java but that is really a secondary concern; you shouldn't be using reflection anyway - At least, there's very few cases where you should.
One of the cases where you can legitimately use reflection is a debugger. The product I happen to work on, BlueJ, is an IDE which includes a debugger and so I have been hit by this a little.
BlueJ is an interesting bird; being designed primarily for beginner programmers, it's approach can be a little different to a normal IDE. BlueJ has an "Object bench" which is an area onto which graphical representations of objects can be placed. The user can then click on these objects and get a menu of methods to call, or likewise inspect the object and see the value of its fields. There are two main ways of an object on the bench: One, by constructing it directly via the interface for doing this which BlueJ provides, or secondly, by calling some method and explicitly putting the result on the bench.
Now, rightly or wrongly, BlueJ has always shown the dynamic type of an object on the bench rather than its static type. That is, if a method is declared to return a Runnable, but it returns an object which is actually a Thread (a subclass of Runnable, or technically an implementor of Runnable seeing as Runnable is a java interface). If you inspect the object, BlueJ will show it as a thread and will allow you to call methods defined by Thread.
All well and good. Enter generics. Suddenly, it's no longer possible to
determine the exact type of an object. Suppose a method returns a
List<?>, that is, a list of an unknown element type.
Via reflection you can determine that the return is actually an
ArrayList, but an ArrayList of what? What should the user be
allowed to add to the list? What type of parameter does its methods take?
In this case the answer is fairly straightforward. The object is of type
ArrayList<?>, and the user shouldn't be allowed to add
any objects into it. Specifically, they should not be able to call any methods
which take the type parameter E (or a dependent of it such as List<E>)
as an argument.
Fine. And you can handle all wildcard types in more-or-less the same manner. Almost.
Consider:
Class A<T,U> { ... }
Class B<T> extends A<T,T> { ... }
Now, imagine some method declared to return an A<? extends Runnable, ? super Thread>,
but which actually returns an instance of B. What then is the exact type of the
returned object?
Again, the exact type cannot be inferred. But this is a very interesting
case: It's possible to infer a type, in this case B<? extends Runnable super Thread>
(or something like that anyway), which is impossible to express in the java
language (yes I have tried; the compiler does not accept that type, or several
variations thereof).
Is such a type useful? well, yes it is. Because there are certain uses of an object which depend on the "? extends ..." notion and others which depend on "? super ...". An object of the mythical type above could be used in either case.
That's my main gripe. The language should support that type construct.
I should add that support for this would be useful in BlueJ, which presently needs to cast an object from the bench to some type in order to allow operations on it.
-- Davin