Переопределяющие методы в Scala

Scala позволяет вам переопределить метод двумя законными способами:

Данный суперкласс:

class A {
  def a = "A"
}

Мы можем переопределить метод "a" на:

class B extends A {
  override def a = "B"
}

и

class B extends A {
  override def a() = "B"
}

оба, похоже, правильно верят метод "a" . Каково конструктивное решение? Зачем позволять "a()" в B переопределять "a" в A?

Ответ 1

Это не всегда было так (из журнала изменений спецификация языка):

Scala версия 2.0 также ослабляет правила переопределения по отношению к пустые списки параметров. Пересмотренное определение соответствующих членов (§5.1.3) позволяет теперь переопределить метод с явным, но пустой список параметров () с помощью метода без параметров и наоборот.

Вы правы, что это похоже на нечетное дизайнерское решение, учитывая, что существуют наблюдаемые различия между безпараметрическими методами и с пустыми списками параметров. Например, предположим, что у вас есть следующее:

class A { def a = "A" }
class B extends A { override def a = "B" }
class C extends A { override def a() = "C" }

Теперь мы можем написать следующее, как ожидалось:

scala> (new B).a
res0: java.lang.String = B

scala> (new C).a
res1: java.lang.String = C

И это:

scala> (new C).a()
res2: java.lang.String = C

Но не это:

scala> (new B).a()
<console>:10: error: not enough arguments for method apply: (index: Int)Char in class StringOps.
Unspecified value parameter index.
              (new B).a()

Итак, Scala делает различие между этими двумя, что, очевидно, должно отразиться на байт-коде. Предположим, что мы скомпилируем следующее:

class A { def a = "A" }
class B extends A { override def a = "B" }

И затем запустите:

javap -verbose B > noArgList.txt

Затем измените код на это:

class A { def a = "A" }
class B extends A { override def a() = "B" }

Перекомпилируйте и запустите:

javap -verbose B > emptyArgList.txt

И, наконец, проверьте различия:

<   MD5 checksum 88aeebf57b645fce2b2fcd2f81acdbbd
---
>   MD5 checksum 3733b3e4181b4b2f4993503d4c05770e
32c32
<   #18 = Utf8               }1A!
                                 \t\t!ICaT-9uszaE\r)\"a\tI!!\"1Q!Dg
jiz\"a\tAQ!BY\t!Y                                                  G.Y11bU2bY|%M[3di\")C%1A(
                 /A$H3)!dGYtwMCQM^1\nyI\"AB*ue&tw\r
---
>   #18 = Utf8               }1A!
                                 \t\t!ICaT-9uszaE\r)\"a\tI!!\"1Q!Dg
jiz\"a\tAQ!BY\t!                                                   G.Y11bU2bY|%M[3di\")C%1A(
                /A$H3)!dGYtwMCQM^1\nyI\"AB*ue&tw\r

Таким образом, существует разница - две версии имеют разные значения для аннотации ScalaSignature.

Что касается изменения в Scala 2.0: спецификация отмечает, что это позволяет:

class C {
    override def toString: String = ...
}

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