Extensions
Kotlin provides an ability to extend a class with new functionality without having to inherit from the class or use design patterns such as Decorator. This is done via special declarations called extensions.
For example, you can write new functions for a class from a third-party library that you can't modify. Such functions are available for calling in the usual way as if they were methods of the original class. This mechanism is called extension functions. There are also extension properties that let you define new properties for existing classes.
Extension functions
To declare an extension function, prefix its name with a receiver type, that means the type being extended. The following adds a swap
function to MutableList<Int>
:
The this
keyword inside an extension function corresponds to the receiver object (the one that is passed before the dot). Now, you can call such a function on any MutableList<Int>
:
This function makes sense for any MutableList<T>
, and you can make it generic:
You declare the generic type parameter before the function name to make it available in the receiver type expression. See Generic functions.
Extensions are resolved statically
Extensions do not actually modify classes they extend. By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on variables of this type.
Extension functions are dispatched statically, that means that they are not virtual by receiver type. An extension function being called is determined by the type of the expression on which the function is invoked, not by the type of the result of evaluating that expression at runtime. For example:
This example prints Shape, because the called extension function depends only on the declared type of the parameter s
, which is the Shape
class.
If a class has a member function, and an extension function is defined which has the same receiver type, the same name, and is applicable to given arguments, the member always wins. For example:
This code prints Class method.
However, it's perfectly OK for extension functions to overload member functions which have the same name but a different signature:
Nullable receiver
Note that extensions can be defined with a nullable receiver type. Such extensions can be called on an object variable even if its value is null, and can check for this == null
inside the body.
This way you can call toString()
in Kotlin without checking for null
: the check happens inside the extension function.
Extension properties
Similarly to functions, Kotlin supports extension properties:
Example:
Companion object extensions
If a class has a companion object defined, you can also define extension functions and properties for the companion object. Just like regular members of the companion object, they can be called using only the class name as the qualifier:
Scope of extensions
In most cases, you define extensions on the top level - directly under packages:
To use such an extension outside its declaring package, import it at the call site:
See Imports for more information.
Declaring extensions as members
Inside a class, you can declare extensions for another class. Inside such an extension, there are multiple implicit receivers- objects members of which can be accessed without a qualifier. The instance of the class in which the extension is declared is called dispatch receiver, and the instance of the receiver type of the extension method is called extension receiver.
In case of a name conflict between the members of the dispatch receiver and the extension receiver, the extension receiver takes precedence. To refer to the member of the dispatch receiver, you can use the qualified this
syntax.
Extensions declared as members can be declared as open
and overridden in subclasses. This means that the dispatch of such functions is virtual with regard to the dispatch receiver type, but static with regard to the extension receiver type.
Note on visibility
Extensions utilize the same visibility of other entities as regular functions declared in the same scope would. For example:
An extension declared at the top level of a file has access to the other
private
top-level declarations in the same file.If an extension is declared outside its receiver type, such an extension cannot access the receiver's
private
members.