Изолированные классы

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

Чтобы описать изолированный класс, укажите модификатор sealed перед именем класса. Изолированный класс может иметь наследников, но все они должны быть объявлены внутри декларации данного изолированного класса (ограничение снято, начиная с версии 1.1 — прим. пер.)

sealed class Expr {
    class Const(val number: Double) : Expr()
    class Sum(val e1: Expr, val e2: Expr) : Expr()
    object NotANumber : Expr()
}

Обратите внимание, что классы, которые расширяют наследников изолированного класса (непрямые наследники) могут быть помещены где угодно, не обязательно внутри декларации изолированного класса.

Ключевое преимущество от использования изолированных классов проявляется тогда, когда вы используете их в выражении when. Если возможно проверить что выражение покрывает все случаи, то вам не нужно добавлять else.

fun eval(expr: Expr): Double = when(expr) {
    is Expr.Const -> expr.number
    is Expr.Sum -> eval(expr.e1) + eval(expr.e2)
    Expr.NotANumber -> Double.NaN
    // оператор `else` не требуется, потому что мы покрыли все возможные случаи
}

Relaxed Rules for Sealed Classes (since 1.1)

Subclasses in the Same File

Since 1.1 you can declare the subclasses of the sealed class on the top-level, with only restriction that they should be located in the same file as the parent class.

Sealed Classes and Data Classes

Data classes can extend other classes, including sealed classes, which makes the hierarchy more usable.

With all the newly supported features, you can rewrite the Expr class hierarchy in the following way:

sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()

fun eval(expr: Expr): Double = when (expr) {
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
}