Annotations: Toward Pluggable Types
One of the new language constructs introduced in Java 5 was annotations. The potential of this feature is larger than many people realize. At the same time, like any construct, it is open to abuse. Hence this blog entry.
One of the more interesting things one can do is define annotations that support optional static analyses. For example, consider an annotation like @NonNull, that signifies that a variable should never hold null. If this annotation is used consistently, a tool can check that such variables indeed never become null at run time. You could say good bye to null pointer exceptions!
This is just one example (albeit, perhaps the most important one) of annotations being used to define an optional type system. It is very important to understand what one can and cannot accomplish in this way.
Since I like being negative, let me start by saying what you cannot do:
You cannot change the run-time behavior of the program
You cannot prevent an otherwise legal program form compiling or executing
Annotations can never be used to change the semantics of a program, or to cause compilation to fail. All annotations do is attach information (metadata) to parts of the program. Tools can then interpret the metadata as they see fit; however, the meaning of a program is fixed by the Java language specification, and cannot be altered.
Occasionally I get asked where in the specs is this stated. The answer, of course, is that the specs don’t have to state any such thing. They already give a definition of what any piece of source code means, and a conformant Java compiler must abide by that specification, and cannot change that meaning.
The fact that a program means the same thing everywhere is at the core of the value proposition of the Java platform. Everyone can read a program and understand what it is going to do; the meaning doesn’t change because of a given installations preferences, local libraries or configurations. That is what helps the Java programming language be such a valuable lingua franca across the industry.
Now, on the positive side, you can plug in a wide variety of semantic analyses or type systems, and get reports on potential errors in your programs. Optional type systems are type systems where the type annotations are syntactically optional, and (more important) the types never influence run-time semantics. Optional types are a perfect fit with annotations.
By definition, one can’t dynamically test for an optional type property of an object. While this may seem to be a limitation, the fact that optional types don’t effect the run time means that different optional type disciplines can co-exist without interacting with each other. That means you can plug in multiple, distinct analyzers/tools//typecheckers. This has the potential to enable pluggable
types.
The annotation system may need a bit of a boost in some cases, because an analyzer may need annotations not just on declarations, but on additional language constructs.
For example, the Javari research project at MIT, which allows you to distinguish between ordinary and read-only references, would require annotations wherever types can appear (including casts and type parameters, which are not currently supported).
In principle, it would be nice if you could attach annotations to every node in the abstract syntax tree. Indeed, even comments could be viewed as annotations. As Michael Van de Vanter has noted, if comments are treated as meaningful metadata belonging to well defined nodes in the AST, refactoring tools can preserve them reliably. However, adding annotations at essentially arbitrary program points poses significant syntactic challenges, so don’t expect that anytime soon.
Posted at 08:17PM Feb 16, 2006 by gbracha in Java | Comments[11]
Posted by Eugene Kuleshov on February 16, 2006 at 10:22 PM PST #
Posted by John Smith on February 16, 2006 at 10:53 PM PST #
Posted by Radu Grigore on February 17, 2006 at 06:05 AM PST #
Posted by Maxim Shafirov on February 17, 2006 at 06:51 AM PST #
John: You misunderstand my inent. @NonNull doesn't do anything at runtime, nor should it. It makes it possible for a tool to check statically that your program simply doesn't ever cause a variable marked with @NoNull to take on the value null.
Radu: ESC/java is really cool technology. It is also very heavyweight, and can do theorem proving. JML is in that same space. They are also intellectually heavyweight things, that won't get used by most programmers. @NonNull would use the xistig framework of APT, hat is widely deployed and well integrated with javac, to do a very simple check. Which means it gets used by many people, and is beneficial to many people.
Maxim: @Override is specified in the JLS, and so it can and does violate the general notion I've outlined - just as the whole type system of the language does. However, you cannot do this for an annotation that is not specified by the JLS.
Posted by Gilad Bracha on February 17, 2006 at 12:10 PM PST #
Posted by Eugene Vigdorchik on February 17, 2006 at 12:47 PM PST #
This is really neat, by the way: NonNull in IntelliJ IDEA.
Posted by Christian Plesner Hansen on February 18, 2006 at 03:04 AM PST #
Posted by Gilad Bracha on February 18, 2006 at 07:57 AM PST #
Posted by Radu Grigore on February 18, 2006 at 08:36 AM PST #
Posted by Gilad Bracha on February 18, 2006 at 12:24 PM PST #
Posted by Dalibor Topic on February 21, 2006 at 08:51 PM PST #