Scala отдает приоритет неявному преобразованию над «естественными» операциями ... Почему? Это ошибка? Или я что-то не так делаю? - PullRequest
9 голосов
/ 21 апреля 2010

Этот простой тест, конечно, работает как положено:

scala> var b = 2
b: Int = 2

scala> b += 1   

scala> b
res3: Int = 3

Теперь я ввожу это в сферу:

class A(var x: Int) { def +=(y:Int) { this.x += y } }
implicit def int2A(i:Int) : A = new A(i)             

Я определяю новый класс и операцию + = с ним, а также удобное неявное преобразование для тех случаев, когда я хочу добавить Int к значению Int Int.

Я никогда не ожидал, что это повлияет на поведение моих обычных операций Int, когда класс «A» совсем не является частью выражения.

Но это так:

scala> var b:Int = 0
b: Int = 0

scala> b += 1

scala> b  
res29: Int = 0

scala> b += 2

scala> b
res31: Int = 0

Похоже, что здесь происходит то, что b: Int неявно преобразуется в «A», которое не связано с какой-либо переменной, и затем + + вызывается для него, отбрасывая результаты.

Кажется, что Scala придает первостепенное значение неявному преобразованию над естественным поведением + = (магия компилятора, а не фактический метод), которое уже определено для Ints. Здравый смысл, а также фон C ++ говорят мне, что последствия должны вызываться только в крайнем случае, когда в противном случае компиляция не удалась бы. Это приводит к нескольким вопросам ...

  • Почему? Это ошибка? Это по замыслу?
  • Есть ли обходной путь (кроме использования "+ =" для моей операции DSL "+ =")?

Спасибо

Ответы [ 5 ]

13 голосов
/ 21 апреля 2010

Как уже отмечали другие, Int не может иметь + = "метод", потому что Int является неизменным. Вместо этого происходит то, что x + = 1 рассматривается как краткая форма для x = x + 1, но только если нет метод с именем + =, который определен для типа. Таким образом, разрешение метода имеет приоритет.

Учитывая, что Scala позволяет вам определять методы + =, а также позволяет делать + + для переменных, могли бы мы изменить приоритет этих двух? То есть попробуйте сначала развернуть + = и только в случае неудачи найдите метод с именем + =?

Теоретически да, но я утверждаю, что это было бы хуже, чем нынешняя схема. Практически нет. В библиотеке коллекций Scala есть много типов, которые определяют метод + для неразрушающее сложение и метод + = для разрушающего сложения. Если бы мы сменили приоритет, то звонок типа

  myHashTable += elem

расширится до

  myHashTable = myHashTable + elem

Таким образом, он создаст новую хеш-таблицу и присвоит ее обратно переменной, а не просто обновит элемент. Не мудрый поступок ...

6 голосов
/ 21 апреля 2010

Из программирования в Scala, глава 17:

Всякий раз, когда вы пишете a + = b, а a делает не поддерживает метод с именем + =, Scala постараюсь интерпретировать это как a = a + b.

Класс Int не содержит метод +=. Однако класс A предоставляет метод +=. Это может вызвать неявное преобразование из Int в A.

3 голосов
/ 21 апреля 2010

Я не думаю, что это ошибка. На самом деле, Int имеет только метод "+", но не имеет метода "+ =". b + = 1 преобразуется в b = b + 1 во время компиляции, если не существует другого неявного, у которого есть метод "+ =".

1 голос
/ 21 апреля 2010

Похоже, что Scala придает первостепенное значение неявному преобразованию над натуральным +=, которое уже определено для Int с.

О какой версии Scala вы говорите? Я не знаю ни одной версии, которая имеет метод += на Int. Конечно, ни одна из все еще поддерживаемых версий не делает, это должна быть какая-то действительно древняя версия, которая у вас есть.

И поскольку += в Int нет, но вы вызываете метод += в Int, Scala пытается удовлетворить это ограничение типа посредством неявного преобразования. *

1 голос
/ 21 апреля 2010

Даже несмотря на объяснение Eastsun, похоже, что это ошибка, и она должна попробовать преобразование b=b+1, прежде чем пытаться неявное преобразование для +=.

Пожалуйста, задайте этот вопрос пользователю scalaсписок адресов электронной почты, отправив письмо по электронной почте scala-user@listes.epfl.ch или посетив сайт n4.nabble.com/Scala-User-f1934582.html.Если это ошибка, вот где она будет замечена и исправлена.

...