Class, extends, enums, switch/case, строки (Kotlin)

Аналогично примеру на Scala, сделал себе аналогичный пример под Kotlin.

// В Kotlin хотя-бы нативно реализован Enum
enum class BikeDrivingSkill {
    Novice, Advanced, Expert
    // Скрытые дополнения под капотом
    // public String enumInst.name   - в строку
    // public Integer enumInst.ordinal - отступ значения 
    // public Array<T> Enum.values() - массив значений
    // public T Enum.valueOf(s)  - значение из строки
}
 
/*
 * Пометки:
 *    open - делают класс/пропсу не final (то-есть можно сделать extends и override)
 *    первая name: String видна только конструктору если не помечена как var или val
 *           class Human(var name: String)     или    class Human(val name: String)
 *      var - можно переписать, val - нет
 */
open class Human(name: String) {
 
    // Делает property c сеттером
    var name: String = name.required()
        // field это текущее значение propery
        // заметка: get() = name    вызывает саму себя и уходит в stackoverflow
        //                          забавно что разрабы это не профиксили
        get() = field
        set (value: String) {
            field = value.required()
        }
 
    // аналогично : public override String toString() { return "..." }
    // "Значок $ - строковая переменная в строке"
    override fun toString() = "Привет меня звать $name."
 
    // Публичная inline функция с void результатом
    fun tellAboutSelf(): Unit = println(this.toString())
 
    // Немного магии, в Котлине можно расширить String ещё одной функцией, внутри этого класса
    private fun String.required() = this.also {
        require(it.trim().isNotEmpty()) {
            "Поле не может быть пустым"
        }
    }
}
 
// Расширяем Человека как Велосипедист
class Bicyclist(name: String, skill: BikeDrivingSkill): Human(name) {
 
    var skill: BikeDrivingSkill = skill
 
    // Переписали и расширили toString()
    override fun toString(): String {
        // switch/case/default реализован вот так
        val skillText = when (skill) {
            BikeDrivingSkill.Novice -> "новичок"
            BikeDrivingSkill.Advanced -> "умею водить велосипед"
            BikeDrivingSkill.Expert -> "отлично управляю велосипедом"
            else -> "Unexpected case: " + skill.name
        }
        // Вызвали super.toString и дополнили своим текстом
        // если надо использовать метод или property, то строка оборачивается ещё в { и }
        return "${super.toString()} И я $skillText."
    }
 
    // Публичная функция с void результатом
    fun train(): Unit {
        if (skill == BikeDrivingSkill.Expert) {
            println("Мне не нужно больше тренироваться, я и так эксперт.")
        } else {
            println("Я пошел тренироваться.")
            val nextId = skill.ordinal + 1 // читать ordinal enum'а
            skill = BikeDrivingSkill.values()[nextId] // следующее значение enum'а
        }
    }
}
 
 
fun main() {
   val kotlin = Bicyclist("Kotlin", BikeDrivingSkill.Novice)
   println(kotlin)
   kotlin.train()
   kotlin.train()
   println(kotlin)
   kotlin.train()
   println(kotlin)
}