[type-annos-observers] Fw: Constraining type annotations to occur just before type

Alex Buckley alex.buckley at oracle.com
Thu Apr 4 13:04:26 PDT 2013


Answers inline.

On 4/3/2013 10:11 PM, Srikanth S Adayapalam wrote:
> More comments from Eclipse JDT team...
>
> Srikanth.
>
> ----- Forwarded by Srikanth S Adayapalam/India/IBM on 04/04/2013 10:40 AM
> -----
>
> From:	Markus Keller/Zurich/IBM at IBMCH
> To:	Srikanth S Adayapalam/India/IBM at IBMIN@IBMDE,
> Date:	04/03/2013 08:32 PM
> Subject:	Re: Fw: Constraining type annotations to occur just before type
>
>
>> I reiterate that compile-time errors are used _only_ when the program's
>> implied behavior would cause a run-time error.
>
> Not really. There are e.g. compile errors if an annotation type cannot be
> resolved, if an @Target annotation is wrongly placed on a non-annotation
> type, or if an @Override annotation doesn't find a super method:
>
> @Target(ElementType.METHOD)
> public class Overriding {
> 	@Override
> 	public void bummer() { }
> }
>
> So the JLS can just as well demand that the compiler verifies that the
> TYPE_USE annotations are at the right position.

I accept that "only" was too strong. It's true that applying an 
annotation of type T to a location not allowed by T's own @Target 
meta-annotation is unlikely to cause a run-time error. Still, it's 
easily recognizable as wrong. The ordering of modifiers is a softer 
topic where new rules are likely to trip up old code - a bad thing.

(The other examples of compile-time errors are a bit tricky. If a 
compiler can't resolve an annotation type, then the compiler can't 
possibly process source correctly which uses annotations of that type; 
any class file emitted would be likely to exhibit a run-time error, so a 
compile-time error is appropriate to prevent that implied behavior. For 
@Override, its semantics do not in my view justify a compile-time error; 
it should have been designed to cause a mandatory compile-time warning, 
a mechanism introduced in Java SE 5.0 for other reasons.)

>> There is some confusion about what happens when an annotation type has
>> TYPE_USE added as a target. No previous code becomes illegal.
>
> It depends on the semantics of the annotation processor. Since JSR 308
> specifies the class file format, it also partially specifies the semantics
> of TYPE_USE annotations. Not the semantics of an annotation itself, but its
> attachment point in the language model. In "@NonNull String[] s3", the
> compilation depends on the annotation's @Target meta-annotation. If it's a
> TYPE_USE annotation, it is now compiled as a Runtime
> [In]VisibleTypeAnnotations. In this example, it's no longer an annotation
> on the whole variable, but an annotation on the "String" type fragment of
> the variable.
>
> Adding TYPE_USE to an existing annotation may be superficially compatible
> (on a syntactical level), but in practice, it's _always_ a breaking change,
> since the TYPE_USE annotation is compiled into different attributes than
> annotations with other ElementTypes, and since it sometimes targets a
> different language element. Adding TYPE_USE to an existing annotation is
> not a source-compatible change if you assume that the annotation has any
> semantics (which is safe to assume, otherwise the annotation wouldn't
> exist). And since we already have a source-incompatible change, it's not a
> big deal if there's an additional restriction on the position of these
> annotations.

Adding TYPE_USE as an additional target of an existing annotation type 
causes no compile-time errors when existing source which uses 
annotations of that type is recompiled. That's basically the definition 
of a source-compatible change. End of story.

It's true that an annotation at a given location may now be _both_ a 
declaration annotation (i.e. on the s3 variable) and a type annotation 
(i.e. on s3's type). It will be reified in the class file in multiple 
attributes, and available to clients of the core reflection and language 
model APIs _if they use the new methods for obtaining type annotations_. 
An existing annotation processor (which uses the SE 7-era methods that 
retrieve only declaration annotations) sees no change.

Bottom line, adding TYPE_USE is compatible in all dimensions.

>>     public static final @Foo @Bar String s;
>
> To generate correct class files, the compiler must know whether the
> annotations are TYPE_USE kinds or not. A purely syntactical parser indeed
> can't tell, but as soon as types are resolved, the information is
> available.

Understood. Rejecting constraints on type annotation placement is not 
about implementation difficulty. It is about three things:

- If TYPE_USE is added as a target for an annotation type which 
previously targeted only declarations, then the annotation can appear at 
the start or end of the modifier list. So, the constraint is not always 
applicable.

- If TYPE_USE is made the _sole_ target for an annotation type, then the 
constraint causes the re-targeting to be a source-incompatible change. 
This is potentially a big problem because the incompatibilities could be 
anywhere. (Fixing up one annotation processor to look in the new 
locations is easy by comparison.)

- In any case, the constraint doesn't make the human reader any wiser 
about what kind of annotation @Foo is, or @Bar is.

Alex


More information about the type-annotations-spec-observers mailing list