Почему объекты-компаньоны класса класса расширяют функциональность?

При создании класса case компилятор создает соответствующий сопутствующий объект с несколькими достоинствами класса case: метод apply factory, соответствующий основному конструктору, equals, hashCode и copy.

Как ни странно, этот сгенерированный объект расширяет функциональность.

scala> case class A(a: Int)                                 
defined class A

scala> A: (Int => A)
res0: (Int) => A = <function1>

Это только в том случае, если:

  • Не указано вручную сопутствующий объект
  • Существует только один список параметров
  • Нет аргументов типа
  • Класс case не является абстрактным.

Похоже, что это было добавлено около двух лет назад. Последнее воплощение здесь.

Кто-нибудь использует это или знает, почему он был добавлен? Он немного увеличивает размер сгенерированного байт-кода со статическими методами пересылки и появляется в методе #toString() для сопутствующих объектов:

scala> case class A()
defined class A

scala> A.toString
res12: java.lang.String = <function0>

UPDATE

Созданные вручную объекты с помощью одного метода apply автоматически не рассматриваются как FunctionN:

object HasApply {
  def apply(a: Int) = 1
}
val i = HasApply(1)

// fails
//  HasApply: (Int => Int) 

Ответ 1

Причина, по которой объекты класса класса класса реализуют FunctionN, заключается в том, что раньше классы case генерировали класс и метод factory, а не объект-компаньон. Когда мы добавили экстракторы в Scala, было более целесообразно превратить метод factory в полный объект-компаньон с методами применения и неприменения. Но тогда, поскольку метод factory соответствовал FunctionN, тоже должен был соответствовать объект-компаньон.

[Edit] Как было сказано, было бы разумно, чтобы объекты-компаньоны отображались как их собственное имя, а не как "функция"

Ответ 2

Хорошо, учитывая, что target.apply(a1, a2, a3 ... aN) в Scala:

  • можно закрепить target(a1, a2, a3 ... aN)
  • - это метод, который должен быть реализован FunctionN

кажется естественным, что объект-компаньон:

object MyClass {
  def apply(a1 : A1, ... aN: AN) = new MyClass(a1, ..., aN)
}

действительно:

object MyClass extends FunctionN[A1, ... , AN, MyClass]{
  def apply(a1 : A1, ... aN: AN) = new MyClass(a1, ..., aN)
}

Итак, добавление кажется мне естественным (я не уверен, почему это кажется "странным" для вас?). Что касается того, действительно ли это что-то добавило; ну, это для кого-то умнее меня!

Ответ 3

Помимо ответа oxbow_lakes о его естественности, часто бывает полезно иметь конструкторы в качестве первоклассных функций, особенно в сочетании с функциями Scala для более высоких порядков. Для (тривиального) примера,

scala> case class Foo(i : Int)
defined class Foo

scala> List(1, 2, 3) map Foo   
res0: List[Foo] = List(Foo(1), Foo(2), Foo(3))

Ответ 4

Welcome to Scala version 2.8.0.RC3 (Java HotSpot(TM) Client VM, Java 1.6.0_20).

scala> case class CC3(i: Int, b: Boolean, s: String)
defined class CC3

scala> CC3
res0: CC3.type = <function3>

scala> CC3.apply(1, true, "boo!")
res1: CC3 = CC3(1,true,boo!)

scala> CC3(1, true, "boo!")
res2: CC3 = CC3(1,true,boo!)