Fw: Constraining type annotations to occur just before type

Alex Buckley alex.buckley at oracle.com
Wed Apr 17 11:32:07 PDT 2013


On 4/12/2013 3:27 AM, Srikanth S Adayapalam wrote:
> ----- Forwarded by Srikanth S Adayapalam/India/IBM on 04/12/2013 03:57 PM
> -----
>
> From:	Markus Keller/Zurich/IBM at IBMCH
> To:	Srikanth S Adayapalam/India/IBM at IBMIN@IBMDE,
> Date:	04/10/2013 09:31 PM
> Subject:	Re: Fw: Constraining type annotations to occur just before type
>
>
>> I don't understand what this "client code" is. The only place where
>> "semantics" is a valid concern is if code starts to use SE 8 API methods
>> to read type annotations, since they will appear on the ground type
>> (String) which may not have been the intended location (String[]) circa
>> SE 7.
>
> With "client code", I mean Java 7 code that uses an annotation and some
> compiler add-on that processes the annotation. E.g. the cited
>      @NonNull final String[] s3;
> or even
>      @NonNull final java.lang.String s4; // legal ONLY for declaration
> annot.
>      final java.lang. at NonNull String s5; // legal ONLY for type-use
> annotations
>
> The @NonNull annotation has some semantics that are defined by the
> annotation type and the compiler add-on. The @NonNull annotation is the
> perfect candidate that wants to migrate to TYPE_USE in Java 8.
>
> My point is that there's no way @NonNull can be a declaration and a
> type-use annotation at the same time, and both of these usages have the
> same semantics. Yes, you can declare separate reflection APIs for
> declaration and type-use annotations, but in the end, the compiler add-on
> that implements the annotation's semantics needs to decide which one to
> use. And it will show different behavior depending on the used API.

It's safe to assume that the author of a type like NonNull always knew 
it "should" have applied to type uses. Unfortunately, it has only been 
possible to apply it to field declarations, so that's where code reads 
it from, via the SE 5.0-era core reflection API. It would not do to make 
those annotations disappear.

Do you agree so far?

So, we let the author of the NonNull type add TYPE_USE as a target. Code 
which uses the SE 5.0-era reflection API will see no difference when 
running on SE 8 or later.

Do you believe this statement about older code to be accurate?

Now suppose some annotation processing code is upgraded (or written from 
scratch) to employ the SE 8-era reflection methods which expose 
annotations on type uses. Then:

1. Where a field declaration involves a non-array type, the upgraded 
code has it easy: it can use the new methods to get annotations on the 
field's type and it will get the same @NonNull as before.

2. Where a field declaration involves an array type, the code will want 
to determine whether the @NonNull is "meant" to apply to the array type 
or to the array type's element type. If NonNull's target is just FIELD, 
it'll be the former; if NonNull's target includes TYPE_USE, it'll be the 
latter.

The determination in 2 is required only because the author of the 
annotation type kept FIELD in the target list for the benefit of unknown 
amounts of code. It's no surprise that the author of an annotation type 
T makes choices which materially affect code which reflects over @T 
annotations.

> The examples s4/s5 with the qualified name shows that it's not even
> possible to use an @Target({ElementType.FIELD, ElementType.TYPE_USE})
> annotation in certain cases that were legal with @Target
> ({ElementType.FIELD}) alone, since the two target kinds _require_ different
> positions in the AST. Therefore, adding TYPE_USE is not a 100%
> source-compatible change, even if you disregard the semantics of the
> annotation.

It's a 100% source-compatible change. Source compatibility means a 
construct which causes no compile-time error in source code circa Java 
SE n still causes no compile-time error in source code circa Java SE n+1.

> The spec should not make it look like it's a valid transition path for an
> existing declaration annotation type to add the TYPE_USE target. I would
> even disallow this combination, since we haven't found a single use case
> where it would make sense.
>
> TYPE_USE should only be used as the sole @Target. Providers of Java 7
> annotation types that want to migrate to TYPE_USE should make it clear that
> this change is not for free for client code in all cases. That standpoint
> also gives us the freedom to constrain TYPE_USE annotations to occur just
> before the type.

I disagree strongly with this position, and here's why. Annotations are 
about three kinds of person:

- the provider of an annotation type (P)
- the applier of annotations in normal code (W)
- the creator of code to reflect over applied annotations (R)

In general, if P's migration to TYPE_USE forces removal of other 
ElementType values from @Target, there will be code from W which no 
longer compiles. (TYPE_USE is reasonably a superset of TYPE and 
TYPE_PARAMETER, but not, say, METHOD.) Since there are probably 10,000 
W's for every P, this is an unacceptable loss of source compatibility.

I would rather let P migrate to TYPE_USE by adding it, which has no 
impact on any W or R person. As W's apply the annotation to type uses, a 
handful of R's will have to do some work to maintain behavioral 
compatibility. That's fine in my book.

And quite separately:

It's a simple fact that a rule to constrain type annotations to occur 
just before the type tells human readers of code almost nothing. Just by 
looking at this code, what do you learn about the targets of Foo and Bar:

   @Foo @Bar String s;

Nothing. Foo and Bar could both target FIELD only, or both target 
TYPE_USE only, in addition to the possibility of Foo targeting FIELD 
only and Bar targeting TYPE_USE only. So the rule does not help any W 
person (of whom there are many) or anyone who reads W's code (of whom 
there are even more).

Alex


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