[type-annos-observers] 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-observers
mailing list