Ary Borenszweig

Ary Borenszweig

Ary is a software craftsman, he is our guru in all code-related problems. Always teaching how to develop the best code with simplicity in mind, he makes everything seem easy no matter how difficult, to the point that nothing seems impossible with him on the team. Very optimistic (sometimes too much), he has the ability to put any idea into code in almost no time.

Why Java generics don’t have problems with right shift operator?

You know that in C++ a template instatiation like:

Foo<Bar<Baz>>
is problematic to parse. Nevertheless, Java seems to repeat history and chosed the same simbols for it’s generics, but nobody seems to complain about it. Do you happen to know why?
I sat for a moment to think about it, consulted the Java Language Specification , and it turns out a Type is defined as follows:
Type:
        Identifier [TypeArguments]{ . Identifier [TypeArguments]} {[]}
        BasicType

TypeArguments:
        < TypeArgument {, TypeArgument} >

TypeArgument:
        Type
        ? [( extends |super ) Type]
Note that as a TypeArgument, only another Type is allowed. This gives us the clue about why this problem is much easier to solve in C++: arguments to generic types are always types, never expressions.
So if a C++ parser already read
Foo<Bar<Baz>>
it may be that Baz resolves to an integer, that Bar is a template that receives an integer as an argument, and so the parser doesn’t know if Baz is the argument of Bar, or if Baz >> somethingElse (which the parser didn’t already read, that is, Baz right shift something else) is it’s argument.
In Java, if the parser is in the same situation, by simply using a stack of previously encountered generic types, this is very easy to solve. Debugging JDT‘s code I found these lines:
// when consuming a rule...
case 538:
  if (DEBUG) {
    System.out.println(
      "ReferenceType2 ::= ReferenceType RIGHT_SHIFT");
  }
  consumeReferenceType2();
  break;
case 544:
  if (DEBUG) {
    System.out.println(
      "ReferenceType3 ::= ReferenceType UNSIGNED_RIGHT_SHIFT");
  }
  consumeReferenceType3();
  break;
As you can see, the case where a type is encountered followed by a right shift is built in the parser, and the consumeReferenceTypeN() methods simply check their generic types stack to see if everything is ok.