Kotlin Download PDF
Table of contents

Kotlin language specification

Version 1.9-rfc+0.1

Marat Akhin

Mikhail Belyaev

Inheritance

Kotlin is an object-oriented language with its object model based on inheritance.

Classifier type inheritance

Classifier types may be inherited from each other: the type inherited from is called the base type, while the type which inherits the base type is called the derived type. The following limitations are imposed on the possible inheritance structure.

A class or object type is allowed to inherit from only one class type (called its direct superclass) and multiple interface types. As specified in the declaration section, if the superclass of a class or object type is not specified, it is assumed to be kotlin.Any. This means, among other things, that every class or object type always has a direct superclass.

A class is called closed and cannot be inherited from if it is not explicitly declared as either open or abstract.

Note: classes are neither open nor abstract by default.

A data class, enum class or annotation class cannot be declared open or abstract, i.e., are always closed and cannot be inherited from. Declaring a class sealed also implicitly declares it abstract.

An interface type may be inherited from any number of other interface types (and only interface types), if the resulting type is well-formed.

Object types cannot be inherited from.

Inheritance is the primary mechanism of introducing subtyping relations between user-defined types in Kotlin. When a classifier type AA is declared with base types B1,,BmB_1, \dots, B_m , it introduces subtyping relations A<:B1,,A<:BmA <: B_1, \ldots, A <: B_m , which are then used in overload resolution and type inference mechanisms.

Abstract classes

A class declared abstract cannot be instantiated, i.e., an object of this class cannot be created directly. Abstract classes are implicitly open and their primary purpose is to be inherited from. Abstract classes (similarly to interfaces) allow for abstract property and function declarations in their scope.

Sealed classes and interfaces

A class or interface (but not a functional interface) may be declared sealed, making it special from the inheritance point-of-view.

Inheritance from built-in types

Built-in types follow the same rules as user-defined types do. Most of them are closed class types and cannot be inherited from. Function types are treated as interfaces and can be inherited from as such.

Matching and subsumption of declarations

A callable declaration DD matches to a callable declaration BB if the following are true.

A callable declaration DD subsumes a callable declaration BB if the following are true.

The notions of matching and subsumption are used when talking about how declarations are inherited and overridden.

Inheriting

A callable declaration (that is, a property or member function declaration) inside a classifier declaration is said to be inheritable if:

If the declaration BB of the base classifier type is inheritable, no other inheritable declaration from the base classifier types subsume BB , no declarations in the derived classifier type override BB , then BB is inherited by the derived classifier type.

As Kotlin is a language with single inheritance (only one supertype can be a class, any number of supertypes can be an interface), there are several additional rules which refine how declarations are inherited.

Overriding

A callable declaration (that is, a property or member function declaration) inside a classifier declaration is said to be overridable if:

It is illegal for a declaration to be both private and either open, abstract or override, such declarations should result in a compile-time error.

If the declaration BB of the base classifier type is overridable, the declaration DD of the derived classifier type subsumes BB , and DD has an override modifier, then DD is overriding the base declaration BB .

A function declaration DD which overrides function declaration BB should satisfy the following conditions.

A property declaration DD which overrides property declaration BB should satisfy the following conditions.

Otherwise, it is a compile-time error.

If the base declaration is not overridable and/or the overriding declaration does not have an override modifier, it is not permitted and should result in a compile-time error.

If the overriding declaration does not have its visibility specified, its visibility is implicitly set to be the same as the visibility of the overridden declaration.

If the overriding declaration does have its visibility specified, it must not be stronger than the visibility of the overridden declaration.

Examples:

open class B {
    protected open fun f() {}
}
class C : B() {
    open override fun f() {}
    // `f` is protected, as its visibility is
    //   inherited from the base declaration
}
class D : B() {
    public open override fun f() {}
    // this is correct, as public visibility is
    //   weaker that protected visibility
    //   from the base declaration
}

open class P {
    open fun g() {}
}

class Q : P() {
    protected open override fun g() {}
    // this is an error, as protected visibility is
    //   stronger that public visibility
    //   from the base declaration
}

Important: platforms may introduce additional cases of both overridability and subsumption of declarations, as well as limit the overriding mechanism due to implementation limitations.

Note: Kotlin does not have a concept of full hiding (or shadowing) of declarations.

Note: if a declaration binds a new function to the same name as was introduced in the base class, but which does not subsume it, it is neither a compile-time error nor an overriding declaration. In this case these two declarations follow the normal rules of overloading. However, these declarations may still result in a compile-time error as a result of conflicting overload detection.