Почему мы можем создавать новые классы, производные от sealed(scala) в Java?

Рассмотрим два класса A и B:

// A.scala
object A {
  sealed abstract class Nat
  case object Zero extends Nat
  case class Succ(n : Nat) extends Nat

  def pp(n : Nat) = n match {
    case Zero => println("Zero")
    case Succ(m) => println("Succ")
    case _ => println("WTF")
  }

  def main(args : Array[String]) = 
    pp(B.f())
}
// B.java
public class B {
    static A.Nat f() {
        return new A.Nat() {};
    }
}

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

$ scala A
WTF

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

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

Вот вопрос: есть ли способ написать действительно закрытые классы (например, ADT), или мне нужно писать фиктивный последний случай в каждом совпадении с шаблоном, чтобы обеспечить безопасность кода?

1 ответ

Решение

Их можно создать из Java, поскольку детали, которые закрывает класс Scala, учитываются только самим компилятором Scala. Компилятор Java не имеет понятия, что A.Nat вообще запечатан.

Также в качестве дополнительного примечания вам нужно пометить Succ как запечатанный, так как в противном случае даже в Scala кто-то может его расширить.

Другие вопросы по тегам