[type-annos-observers] Constraining type annotations to occur just before type
Srikanth S Adayapalam
srikanth_sankaran at in.ibm.com
Tue Apr 2 01:02:47 PDT 2013
[I am sorry I was away from my mail for a few days and couldn't
forward this feedback from Markus Keller of the Eclipse JDT team
earlier - Srikanth]
----------------8<------------
> However, we cannot say that decl. annotations must come before
> traditional modifiers (private/public/static/final etc) because it has
> been legal since Java SE 5.0 to mix them up. The only rule which could
> possibly be added is "type annotations are not modifiers, and occur
> after all modifiers (which include declaration annotations)".
I agree we can't fix the Java 5 mix-up. The proposed rule sounds good.
> I personally remain to be convinced that this rule is necessary.
Allowing the TYPE_USE annotations not right in front of the variable or
return type is even more absurd if the type is an array or qualified type:
// Allowed (should be disallowed):
@NonNull final String s2 = new @NonNull String();
// The @NonNull annotates "String", not the whole return type "String[]":
@NonNull final String[] s3 = new @NonNull String[] { };
// Not allowed (annotation on package "java"):
@NonNull final java.lang.String s4 = new @NonNull String();
// What the user meant:
final java.lang. at NonNull String s5 = new @NonNull String();
I don't see any practical value in allowing TYPE_USE annotations to show up
in front of other modifiers, but there's a clear reduction of confusion if
they are only allowed at the end of the modifiers list.
The compiler currently doesn't care much about the position of the
annotations because it only marginally processes the annotations (for code
generation). On the other hand, every tool that processes annotations is
also affected by the torn-apart type references, since the AST becomes
irregular.
For refactoring tools, fetching the information from everywhere is a mess,
and trivial rewrite operations like qualifying a type reference (compare s2
with s4) need much more logic than necessary. For users who have to read or
manually refactor such code, it's an even bigger mess.
Since "conventions" in the JLS are not binding, they are not a big help in
practice. Conventions are fine to help users avoid bugs from earlier
versions of the spec. But a new spec should not contain new conventions if
it's trivial to just set a standard and avoid digressions.
Let's list the arguments:
Pro rule:
* Easier to understand for everybody
* Easier to process by tools and humans that refactor code
* If necessary, rule can be relaxed later; but it cannot be added later
Contra rule:
* Source code incompatibility with pre-Java-8 hacks that use
declaration annotations to stand for type annotations.
=> When an annotation becomes a TYPE_USE annotation, existing code needs
to be massaged anyway. As the examples above show, the pre-Java-8 hacks are
incompatible with Java 8 anyway. I'd even declare it a feature that users
are forced to make a pass over their source in that case.
* Rule cannot be implemented by the parser since the grammar is ambiguous.
The grammar cannot be fixed, since the parser cannot distinguish TYPE_USE
from other annotations in these cases (the parser did not resolve the
@Target yet). The rule needs to be enforced at a later compilation step.
* Rule needs to be implemented
More information about the type-annotations-spec-observers
mailing list