E041: Mixed Left And Right Associative Ops — 좌결합·우결합 연산자를 섞어 썼어요

E041: Mixed Left And Right Associative Ops — 좌결합·우결합 연산자를 섞어 썼어요

결합성(associativity) 이 서로 다르지만 우선순위(precedence) 가 같은 연산자들을 괄호 없이 한 표현식에 함께 사용했을 때 이 에러가 나와요.

출처: Scala 3 Reference

본문

Scala에서 콜론(:)으로 끝나는 연산자는 우결합(right-associative) 이에요. 나머지 연산자는 모두 좌결합(left-associative) 이고요. 우선순위가 같은데 결합성이 다른 두 연산자를 함께 쓰면, 컴파일러가 평가 순서를 정할 수 없어요.

중위 연산자(infix operator)의 우선순위는 연산자의 첫 번째 문자로 결정돼요. 아래는 우선순위가 높아지는 순서로 문자를 나열한 거예요.

  • (모든 문자)
  • |
  • ^
  • &
  • = !
  • < >
  • :
  • + -
  • * / %
  • (그 외의 모든 특수 문자)

예제 (Example)

extension (x: Int)
  def +: (y: Int): Int = x + y
  def +* (y: Int): Int = x * y

def example = 1 +: 2 +* 3

+:는 우결합, +*는 좌결합이에요. 둘 다 첫 문자가 +라서 우선순위가 같은데, 결합성이 달라서 이들을 섞어 쓰면 애매해져요.

오류 메시지 (Error)

-- [E041] Syntax Error: example.scala:5:19 -------------------------------------
5 |def example = 1 +: 2 +* 3
  |                   ^
  |+: (which is right-associative) and +* (which is left-associative) have same precedence and may not be mixed
  |-----------------------------------------------------------------------------
  | Explanation (enabled by `-explain`)
  |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  | The operators +: and +* are used as infix operators in the same expression,
  | but they bind to different sides:
  | +: is applied to the operand to its right
  | +* is applied to the operand to its left
  | As both have the same precedence the compiler can't decide which to apply first.
  |
  | You may use parenthesis to make the application order explicit,
  | or use method application syntax operand1.+:(operand2).
  |
  | Operators ending in a colon : are right-associative. All other operators are left-associative.
  |
  | Infix operator precedence is determined by the operator's first character. Characters are listed
  | below in increasing order of precedence, with characters on the same line having the same precedence.
  |   (all letters)
  |   |
  |   ^
  |   &
  |   = !
  |   < >
  |   :
  |   + -
  |   * / %
  |   (all other special characters)
  | Operators starting with a letter have lowest precedence, followed by operators starting with `|`, etc.
   -----------------------------------------------------------------------------

해결 방법 (Solution)

괄호로 적용 순서를 명확히 하거나, 메서드 호출 문법(operand1.+:(operand2))을 사용하면 돼요.

// Use parentheses to make the order explicit
extension (x: Int)
  def +: (y: Int): Int = x + y
  def +* (y: Int): Int = x * y

def example = (1 +: 2) +* 3
// Or use method call syntax
extension (x: Int)
  def +: (y: Int): Int = x + y
  def +* (y: Int): Int = x * y

def example = (1.+:(2)).+*(3)

더 알아보기 (Learn more)