[type-annos-observers] ordering of annotated array brackets

Markus Keller markus_keller at ch.ibm.com
Tue Mar 4 14:17:21 UTC 2014


Hi Werner, Alex

> Markus, you say that this behavior "totally makes sense". Can you 
elaborate why?

AFAIK, the primary goal of the C-style "brackets after identifier" 
notation is not the "mixed notation" as in Werner's examples (actually 
discouraged in 10.2), but to allow a declaration of a series of variables, 
where some of the variables have additional array dimensions:

private @A int @B [] fieldBase, fieldExtra @C [];

Here, fieldBase obviously has type @A int @B []. fieldExtra has the type 
of fieldBase, plus the extra dimension @C []. I think it makes sense to 
arrange it so that an element of array fieldExtra has the same type as 
fieldBase. To achieve that, the @C [] must be the logically "outermost" 
type. And by the argumentation in 
http://types.cs.washington.edu/jsr308/specification/java-annotation-design.html#array-syntax 
and the example in JLS8 9.7.4, the array bracket ordering for an 
outside-in traversal is from left to right, so the @C [] must be inserted 
in front of @B [], which gives the equivalent declaration

private @A int @C [] @B [] fieldExtra;

I agree it's not pretty, but as said in java-annotation-design.html, the 
notation is bound by history. And the alternative is IMO worse: If 
fieldExtra had the type @A int @B [] @C [], then its component type would 
be @A int @C [] -- a type that's even more disconnected from the original 
variable declaration.

Thanks,
Markus


Werner Dietl <wdietl at gmail.com> wrote on 2014-03-04 04:48:45:

> Hi Markus, Alex,
> 
> the current javac behavior is as Markus describes, but might be an
> artifact of pre-type-annotation code.
> At the moment in test case:
> 
> tools/javac/annotations/typeAnnotations/referenceinfos/Fields.java
> 
> we only test having either all or none of the array dimensions before
> the field name (tests fieldAsArray and fieldAsArrayOld).
> I expanded the test and see the behavior that Markus describes.
> The behavior for variable declarations and method return types (with
> array dimensions after the parameter list) is consistent.
> 
> Markus, you say that this behavior "totally makes sense". Can you 
elaborate why?
> I agree with Alex that having the post-identifier array dimensions
> become the outermost dimensions seems counter-intuitive and makes the
> code harder to read.
> Wouldn't it be easier to read if all of these fields had the same type:
> 
> @TD String @TA [] @TB [] @TC [] test;
> @TD String @TA [] @TB [] test @TC [];
> @TD String @TA [] test @TB [] @TC [];
> @TD String test @TA [] @TB [] @TC [];
> 
> cu, WMD.
> 
> On Mon, Mar 3, 2014 at 2:51 PM, Alex Buckley <alex.buckley at oracle.com> 
wrote:
> > Hi Markus,
> >
> > Thanks for your mail and excellent test case.
> >
> > However, I don't see why the post-identifier "@C []" should be the 
outermost
> > dimension, as if "int @C [] @B []" had been written. Certainly there 
was no
> > hint of this in the January 2013 thread "Annotations on extended 
dimension
> > in method declarations".
> >
> > I think the "followed by ..." wording of 10.2 indicates that "@C []" 
should
> > be the innermost (deepest) dimension, as if "int @B [] @C []" had been
> > written.
> >
> > I am not clear if javac or java.lang.reflect is assembling the full 
array
> > type in (what I consider to be) the wrong order. Werner, if you're 
reading
> > this, can you help us out?
> >
> > Alex
> >
> >
> > On 3/3/2014 8:29 AM, Markus Keller wrote:
> >>
> >> JLS8 10.2 says:
> >> "In a variable declaration (§8.3, §8.4.1, §9.3, §14.14, §14.20) 
except for
> >> a variable
> >> arity parameter, the array type of a variable is denoted by the array 
type
> >> that appears
> >> at the beginning of the declaration, followed by any bracket pairs 
that
> >> follow the
> >> variable's Identifier in the declarator."
> >>
> >> This was fine for Java < 8, where array dimension brackets were
> >> indistinguishable. But with type annotations, the order of annotated
> >> dimension brackets matters.
> >>
> >> Example:    private @A int @B [] field @C [];
> >>
> >> In "1.8.0-b129", reflection says the type of "field" is "@A int @C [] 
@B
> >> []", and that totally makes sense. See also [1].
> >>
> >> The paragraph should e.g. say:
> >> "[..] the array type of a variable is denoted by the element type at 
the
> >> beginning of the declaration, followed by any (potentially annotated)
> >> bracket pairs that follow the variable's Identifier in the 
declarator,
> >> followed by any (potentially annotated) bracket pairs of the array 
type at
> >> the beginning of the declaration."
> >>
> >> The ordering of consecutive array dimension brackets is currently 
also
> >> undefined by the spec. There's just an informal example in 9.7.4 
(which is
> >> good; it's just not a spec).
> >>
> >> Regards,
> >> Markus
> >>
> >>
> >> [1]  Executable snippet to test reflection:
> >>
> >> import java.lang.annotation.*;
> >> import java.lang.reflect.*;
> >> import java.util.stream.*;
> >>
> >> @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME)
> >> @interface A {}
> >> @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME)
> >> @interface B {}
> >> @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME)
> >> @interface C {}
> >>
> >> public class Snippet {
> >>      private @A int @B [] field @C [];
> >>      private @A int @C [] @B [] fieldNormal;
> >>      private @A int @B [] fieldBase, fieldExtra @C [];
> >>
> >>      public static void main(String[] args) throws Exception {
> >>          printField("field");
> >>          printField("fieldNormal");
> >>          printField("fieldBase");
> >>          printField("fieldExtra");
> >>      }
> >>
> >>      private static void printField(String name) throws
> >> NoSuchFieldException {
> >>          System.out.printf("%-12s %s\n", name + ":",
> >> toString(Snippet.class.getDeclaredField(name).getAnnotatedType()));
> >>      }
> >>
> >>      private static String toString(AnnotatedType annotatedType) {
> >>          StringBuilder sb = new StringBuilder();
> >>          while (annotatedType instanceof AnnotatedArrayType) {
> >>              sb.append("
> >> ").append(toString(annotatedType.getAnnotations())).append("[]");
> >>              annotatedType = ((AnnotatedArrayType)
> >> annotatedType).getAnnotatedGenericComponentType();
> >>          }
> >>          Type type = annotatedType.getType();
> >>          sb.insert(0, type.toString());
> >>          sb.insert(0, toString(annotatedType.getAnnotations()));
> >>          return sb.toString();
> >>      }
> >>
> >>      private static String toString(Annotation[] annotations) {
> >>          return Stream.of(annotations).map(Snippet::toSimpleString).
> >>                  collect(Collectors.joining(" ", "", " "));
> >>      }
> >>
> >>      public static String toSimpleString(Annotation a) {
> >>          return "@" + a.annotationType().getSimpleName();
> >>      }
> >> }
> >>
> >
> 
> 
> 
> -- 
> http://www.google.com/profiles/wdietl
> 



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