Каковы практические преимущества маркировки case-классов как final в scala

Некоторые библиотеки с открытым исходным кодом похоже, что у твиттеров есть соглашение о маркировке классов case как final.

Моя команда решает, следует ли принимать это соглашение, но мы еще не понимаем, за что это нужно. В настоящее время единственное возможное преимущество, которое я могу ощутить, - это то, что он предотвращает случайное наследование от case-классов.

Но есть ли другие преимущества? Уменьшает ли это время компиляции или позволяет компилятору добавлять внутренние оптимизации?

Я надеялся, что это поможет в обнаружении недостающих значений в совпадениях с образцом, но, похоже, этого тоже не происходит. В таком простом скрипте компилятор генерирует предупреждение для matchSealed, но не для matchFinal:

sealed case class Sealed(one: Option[Int], two: Option[Int])

def matchSealed(s: Sealed): Unit = s match {
  case Sealed(Some(i), None) => println(i)
}

final case class Final(one: Option[Int], two: Option[Int])

def matchFinal(f: Final): Unit = f match {
  case Final(Some(i), None) => println(i)
}

Мое впечатление о final таково, что это более сильное ограничение, чем sealed, поэтому странно, что это не вызывает предупреждения.


person rmin    schedule 13.04.2016    source источник
comment
В этой статье говорится об этой проблеме в ее заключительные комментарии. Автор использует final, говоря, что это более наглядно, это соглашение и открывает возможности для оптимизации компилятора (хотя об этом ничего не известно).   -  person rmin    schedule 20.04.2016


Ответы (1)


Вот объяснение некоторых преимуществ:

Последний класс case не может быть расширен никаким другим классом. Это означает, что вы можете дать более надежные гарантии того, как ведет себя ваш код. Вы знаете, что никто не может создать подкласс вашего класса, переопределить некоторые методы и сделать что-то глупое. Это замечательно, когда вы отлаживаете код - вам не нужно искать по всей иерархии объектов, чтобы выяснить, какие методы на самом деле вызываются.

Конечно, превращение классов в окончательные означает, что вы теряете форму расширяемости. Если вы действительно хотите разрешить пользователям реализовывать функциональные возможности, вам следует обернуть эту функциональность в трейт и вместо этого использовать шаблон класса типа.

person marcospereira    schedule 13.04.2016
comment
Спасибо @marcospereira. Так что вроде как наследование просто прекращается. Для нас это не большая победа, потому что мы все равно не пытаемся расширять классы case. Я надеюсь, что есть еще несколько преимуществ. - person rmin; 14.04.2016