From 2dea17a3a937940bd1f668307db7110edc6b9da3 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 13 May 2015 14:23:09 +0300 Subject: [PATCH] Final specification for sealed class hierarchies, additional words about sealed when optimization --- spec-docs/sealed-hierarchies-and-when.md | 53 +++++++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/spec-docs/sealed-hierarchies-and-when.md b/spec-docs/sealed-hierarchies-and-when.md index 2ee743204b7..a76c63d6c89 100644 --- a/spec-docs/sealed-hierarchies-and-when.md +++ b/spec-docs/sealed-hierarchies-and-when.md @@ -5,7 +5,41 @@ Goals: ## Discussion -One option would be to make `when` understand hierarchies like this one: +### Sealed Class Option + +**This option is chosen as final.** + +Special `sealed` keyword is introduced to mark base classes for sealed hierarchies, like this: + +``` kotlin +sealed class Type () { + class Named(val name: String) : Type() + class Nested { + class Function(val param: Type, val result: Type): Type() + } + object Top: Type() +} +// ... +when (type) { + is Named -> println(name) + is Nested.Function -> println("$param -> $result") + // Alternatively, we can omit is here + is Top -> println("TOP") +} +``` + +It's assumed here that sealed class can be subclassed only by nested classes or objects, both with any level of nesting, +but not by local classes of any sort. So the `when` example would operate correctly. + +Sealed classes are abstract by default, so abstract modifier is redundant +(otherwise `when` requires additional case covering all other cases: is Type). +Sealed classes can never be open or final. +Sealed interfaces are prohibited, otherwise Java classes could easily inherit them. +Sealed objects are also not possible, because we cannot inherit from object. + +### Private Constructor Option + +Another option would be to make `when` understand hierarchies like this one: ``` kotlin abstract class Type private () { @@ -24,6 +58,21 @@ when (type) { is Function -> println("$param -> $result") is Top -> println("TOP") } - ``` +However, class with a private constructor can also be derived as a local class, that provides a problem for this option implementation. + +## Future When Optimization + +It's possible to optimize when on sealed in the way like when on enum or when on string. +There are the following opportunities, all of them use `KSealed` interface with some `final` identification method: + +* use `ordinal()` method, which is implemented like enums, so the first descendant has an ordinal 0, +second 1 and so on. When on sealed organized like when on enum. Drawback: reordering breaks client's code. +* use `sealedName()` method returning a fully qualified class name of a direct sealed descendant. +When on sealed organized like when on string. Drawback: extra efforts. +* use `sealedId()` method returning a hash code of a direct sealed descendant fully qualified class name. +Drawbacks: possible collisions, including an opportunity to rename some member and get hash code of another member, +which breaks client's code in a dramatic way. + +After optimization, `instanceof KSealed` should be checked at run-time before applying it.