Arrow (->) operator precedence/priority is lowest, or priority of assignment/combined assignment is lowest?

后端 未结 2 1862
梦毁少年i
梦毁少年i 2021-02-13 00:27

JLS:

The lowest precedence operator is the arrow of a lambda expression (->), followed by the assignment operators.

相关标签:
2条回答
  • 2021-02-13 00:34

    Note the sentence preceding the quoted JLS text:

    Precedence among operators is managed by a hierarchy of grammar productions.

    The grammar of the Java language determines which constructs are possible and implicitly, the operator precedence.

    Even the princeton table you’ve linked states:

    There is no explicit operator precedence table in the Java Language Specification. Different tables on the web and in textbooks disagree in some minor ways.

    So, the grammar of the Java language doesn’t allow lambda expressions to the left of an assignment operator and likewise, doesn’t allow assignments to the left of the ->. So there’s no ambiguity between these operators possible and the precedence rule, though explicitly stated in the JLS, becomes meaningless.

    This allows to compile, e.g. such a gem, without ambiguity:

    static Consumer<String> C;
    static String S;
    public static void main(String[] args)
    {
      Runnable r;
      r = () -> C = s -> S = s;
    }
    
    0 讨论(0)
  • 2021-02-13 00:56

    First, let's explain the practical issue here.

    Assuming you have a definition like

    IntUnaryOperator op;
    

    The following is syntactically accepted, and works as expected:

    op = x -> x;
    

    That is, we have an identity function on int assigned to the op variable. But if = had a higher priority, we'd expect Java to interpret this as

    (op = x) -> x;
    

    Which is not syntactically valid, thus should be a compile error. Hence, assignment does not, in practice, have higher precedence than the arrow.

    But the following is also OK (assume t is a class/instance variable of type int):

    op = x -> t = x;
    

    This compiles, and the function, if applied, assigns the value of the operand to t and also returns it.

    This means that the arrow doesn't have higher precedence than the assignment t = x. Otherwise it would have been interpreted as

    op = ( x -> t ) = x
    

    and clearly, this is not what happens.

    So it seems that the operations have equal precedence. What's more, that they are right-associative. This is implied from the grammar at JLS chapter 19:

    Expression:
      LambdaExpression
      AssignmentExpression
    
    LambdaExpression:
      LambdaParameters -> LambdaBody
    
    ...
    
    LambdaBody:
      Expression
      Block
    

    So the right side of the lambda body gets us back to Expression, which means we can either have a (higher priority) lambda inside it, or a (higher priority) assignment in it. What I mean by "higher priority" is that the deeper you go through the production rules, the earlier the expression will be evaluated.

    The same is true for the assignment operator:

    AssignmentExpression:
      ConditionalExpression
      Assignment
    
    Assignment:
      LeftHandSide AssignmentOperator Expression
    

    Once again, the right side of the assignment throws us back to Expression, so we can have a lambda expression or an assignment there.

    So rather than relying on the JLS text, the grammar gives us a well defined description of the situation.

    0 讨论(0)
提交回复
热议问题