Monday, April 18, 2011

Follow-up: Why I consider these features missing in Java

Some time ago I created a list of features I consider missing in the current Java implementation. As I recently realized it makes sense to provide reasoning for some of them to be in the list.

Properties accessible as such via reflection
Support for properties in Java6 has been very weak since the very beginning. I see problems in at least three areas:
1) Language/compiler - there is notion of property in Java language so there is no convenient syntax to define and use a property. Current approach is to rely on JavaBeans conventions for property naming which I find quite ridiculous and to some extent limited;
2) JVM/reflection - properties are not represented as reflection-accessible objects so for a class there is no straightforward way to enumerate all properties or get a specific property by name. Additionally there is no direct way to access related annotations.
3) Class libraries - properties had been introduced long ago as part of java.beans package mostly focused on GUI-related use of JavaBeans. Hence employing java.beans for anything but GUI is not common. Moreover, the java.beans.Introspector class, the entry-point of the package, is known to have some issues related to inheritance and Generics which makes it not quite reliable.
These problems lead to a situation where any project relying on the concept of property has to build custom implementations of the very same functionality thus taking away precious resources. Adopting the best practices (e.g. from .NET) in Java would let us stop reinventing the wheel.
'yield'-like keyword or Generators
.NET yield provides simple syntax for exposing elements while iterating over a possibly complex structure (like a tree or a chain of lists/arrays, etc). Unless compiler provides support for that a state machine must be constructed to maintain the state of iteration. That also implies a set of unit-tests must be written to verify correctness. Again, we have non-productive waste of resources while this can easily be provided by the compiler.
'as' keyword 
That one is simple. Instead of

if (x != null && (x instanceof T)) {
   T y = (T) x;
   ...
}
I would write
T y = x as T;
if (y != null) {
   ...

avoiding the extra cast. 
Human-usable Generics
As of Java Generics my opinion is that a language feature is counter-productive if it requires too many words for explanation of both the intended usages and the possible pitfalls. That just too much information to learn with no reasonable gain. The biggest problem is no matter how well you understand Generics some simple things (e.g. converting from Collection<T> to T[] or instantiating an object of the type variable T) are not as simple as they must be.
Byte-code emitter API
Actually a version of Apache BCEL library is present in the class library. However it is internal and hence creating dependencies on it is not advisable. Since byte-code engineering is very popular nowadays I would prefer corresponding facilities to be publicly accessible as a part of standard Java distribution so not to drag any extra jars into a project.
Unified interfaces and compiler support for events
Events are actually invocation lists that only allow addition and removal of a listener. These two operations are what constitutes their outbound interface. Instead of creating a bunch of add..Listener()/remove...Listener() methods I could simply expose an event object to the caller. Actual invocation list implementation may vary to offer for example certain thread-safety guarantees - copy-on-write, fully synchronized, etc. Based on C# experience I can tell this makes code much simpler and more readable. Additionally, once event objects are exposed via reflection binding of components to each other is also facilitated. When combined with function objects this can greatly contribute to the overall code maintainability.
Verbatim string literals
Nowadays it's quite common to embed pieces of different DSL into the code itself rather than keep it in external XML or configuration files. Good examples are Hibernate/JPA QL statements, SQL, regular expressions, StringTemplate templates, etc. Using indentation and spacing is usually preferable for those statements as to keep them easily readable. Standard string literals do not allow multi-line values which is often worked around by using string concatenation. The resulting mixture of double-quotes, backslashes and plus signs is quite messy and error-prone. There are tools that allow editing DSL and copy-pasting it to and from Java code with proper escaping but that in some way defeats the idea of keeping DSL in java source files.
Known problems with verbatim literals - 1) what to use as the end-of-line (EOL) character - LF/CR/CRLF or system-dependent, and 2) how to handle white-space characters if they matter.
The most of DSLs simply ignore white-space so they do not care of what character is used to indicate line breaks and what spacing or indentation is applied in the statement. However there are cases when EOL encoding is important like, for example, in an embedded template that is used to produce a text file in the file system of the underlying platform. Also templates that produce human-intended text may require accurate white-space handling.
In those rare cases where line break really matters a specially designated compile-time annotation can be applied to the variable so to indicate the desired end-of-line sequence. When compiler meets the annotation it replaces the literal with the equivalent string concatenation interleaved with the proper EOL sequences.
White-space handling is a very different problem. I am inclined to think that verbatim literals are not at all suitable for the purpose of storing white-space sensitive strings.

No comments:

Post a Comment