Extensions in Kotlin

You are here:
Estimated reading time: 4 min

In this tutorial, we will be learning how to use extension functions in Kotlin.

Kotlin provides us the facility to add more functionality to existing classes without having to inherit them.

Functions that are added to an existing class without inheriting from it are known as Extension functions.

Syntax

An extension function in Kotlin can be defined by writing the name of the class that the function is to be added to, followed by the name of the function and its definition as shown below:

fun className.functionName(paramName:paramType) : functionReturnType{
    //function body
}

Extending User Defined Classes using Extension Functions

class Avengers(var name : String, var role : String, var Strength: Int, var Weakness: Int){
    fun printDetails():Unit{
        println("$name is $role.")
    }
}
fun main(){
    fun Avengers.calculatePower(avengerStrength:Int, avengerWeakness:Int):Unit{
        var totalPower=avengerStrength-avengerWeakness
        println(totalPower)
    }
    val newAvenger=Avengers("Anthony Mackie","Captain America",5990,1440)
    newAvenger.printDetails()
    newAvenger.calculatePower(newAvenger.Strength,newAvenger.Weakness)
}

In the above example, the class Avengers is a predefined class having class attributes name, role, Strength and Weakness and a class method printDetails that prints the name and role of the current object/instance.

To add another function to this predefined class without having to inherit from it, we define an extension function.

Here, calculatePower is the extension function and it provides the functionality of calculating and printing the value of the variable power by subtracting Weakness from Strength.

As you can see, despite of the fact that the function calculatePower is defined outside of the class Avengers, we are still able to call the function using the object of the class Avengers, newAvenger, which implies that the function calculatePower is a part of the class Avengers and is hence, an extension function.

Extending Library Classes using Extension Functions

Kotlin also allows extending the functionality of library functions using extension functions.

fun main(){
    var num=56
    println(num.increaseByTen())
}
fun Int.increaseByTen():Int{
    return this+10
}

In the above example, we are extending the library class Int using the increaseByTwo function. this refers to the object through which the function increaseByTwo is called. Therefore, in the function increaseByTen, the value of the variable num is increased by 10.

Extensions are resolved statically

Extension functions in Kotlin are resolved statically.

The 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. 

This means that the extension functions are resolved during compile time, based on the type of object that the extension function is called upon i.e. extension functions are called, based on the type of expression they are called upon, rather than the type of value that the expression evaluates to.

When an extension function is defined for a class, it is not actually inserted as a member into the class. Extensions do not modify the classes they extend. Instead, they are merely new functions which can be called by using the dot notation.

open class Marvel

class Avengers: Marvel()

fun Marvel.getLocation(): String {
    return "Inside Marvel Universe"
}

fun Avengers.getLocation(): String{
    return "Inside Avengers Franchise"
}

fun printClassLocation(m: Marvel) {
    println(m.getLocation())
}    

fun main(){
    printClassLocation(Avengers())
}

The above example gives the output “Inside Marvel Class”.

This is because the extension function to be called (in this case, getLocation) depends only on the type of the parameter m, which is object of the Marvel class.

Extensions v/s Member Functions

When and extension function declared with the same name and parameter list as a member function, then the member function always has higher priority over the extension function.

class Student(var name:String, var grade:String){
    fun printDetails(){
        println("$name - $grade")
    }
}
fun Student.printDetails(){
    println("This is an extension function. $name - $grade")
}
fun main(){
    var s=Student("John","9th")
    s.printDetails()
}

In the above example, the member function shadows the extension function as both of them have the same name and parameter list.

However, overloading a member function with an extension function is perfectly fine, if the extension function has the same name but a different parameter list.

class Student(var name:String, var grade:String){
    fun printDetails(){
        println("$name - $grade")
    }
}
fun Student.printDetails(rollNum:Int){
    println("This is an extension function. $name, $rollNum - $grade")
}
fun main(){
    var s=Student("John","9th")
    s.printDetails(34)
}

Extension Functions as Nullable Receiver

Extension functions can be defined with a nullable receiver type i.e. an extension function can be called upon an object even if that object’s value is null.

To check the nullability of an object’s value, you can use the condition if(this==null). The condition will return true if the object’s value is null. If the object’s value is not null, it will return false.

You can also declare an extension function in Kotlin with a nullable receiver by writing the class name followed by ?. followed by the function name and definition.

fun className?.functionName(parameterList):returnType{

//function body

}

class Planet(){
    var planetName:String="unknown"
}
fun Planet?.getName(): String{
    if(this==null) return "null object"
    return this.planetName
}
fun main(){
    var p=Planet()
    p.planetName="Mercury"
    println(p.getName())
    println(null.getName())
}

Companion Object Extensions

An object declaration inside a class can be marked with the companion keyword i.e. a companion object is an object which is declared inside a class and marked with the companion keyword.

Members of the companion objects in Kotlin can be accessed directly using the class name (like static in Java) i.e. it is not necessary to create an object of the class to access companion object members of that class.

class className{
    companion object{
        fun printSomething(){
            println("Defined inside companion object")
        }
    }
}
fun main(){
    className.printSomething()
}

If a class has a companion object defined, then a static extension function can be added to this class by inserting “.Companion” between the class name and the function name:

class className{
    companion object{
        fun printSomething(){
            println("Defined inside companion object")
        }	
    }
}
fun className.Companion.printNew(){
    println("Companion Object Extension")
}
fun main(){
    className.printNew()
}

Extension Properties

Kotlin also allows us to add properties/attributes to a predefined class without having to inherit from that class. These are called extension properties.

You can also create Extension properties with overridden getters and setters.

But it is not possible to create an extension property with a backing field because it is not allowed to add a field to an existing class. This is also why initializers are not allowed for extension properties.

Other articles related to Functions:

Functions in Kotlin

Default and Named Arguments in Kotlin

Go through more of our extensive and in-depth Kotlin articles here.

References:

https://kotlinlang.org/docs/tutorials/kotlin-for-py/extension-functionsproperties.html

https://kotlinlang.org/docs/reference/functions.html

https://kotlinlang.org/docs/reference/extensions.html

Was this article helpful?
Dislike 0
Views: 11