Kotlin Extension Function
Kotlin provide the feature of add new functionality to a class without use of the concept of inheritance This feature is called Extension Function.
Why Kotlin Extension Function ?
The purpose of extension function is to add a new function to the existing class. Simply adds a particular function to a predefined class without declaring it inside the class and the new functions actually behaves just like the static functions in case of Java now practically also during the compilation the kotlin compiler also converts these functions into the static functions internally that happens in background.
Example
// A sample class to demonstrate extension functions
class Circle (val radius: Double){
// member function of class
fun area(): Double{
return Math.PI * radius * radius;
}
}
fun main(){
// Extension function created for a class Circle
fun Circle.perimeter(): Double{
return 2*Math.PI*radius;
}
// create object for class Circle
val newCircle = Circle(2.5);
// invoke member function
println("Area of the circle is ${newCircle.area()}")
//invoke extension function
println("Perimeter of the circle is ${newCircle.perimeter()}")
}
Output
Area of the circle is 19.634954084936208
Perimeter of the circle is 15.707963267948966
Advantages
- The extension function has few properties such as they can become part of your user defined class (example, student, employee ,user and so on) and also become part of the predefined classes such as array, string, integer or any other predefined classes that comes with the Kotlin SDK.
- An extension declared inside the class then it can access other private member of the same class.
- If an extension is declared outside the class, it can not access other private member of the same class.
Extended library class using extension function
Kotlin also allows library classes to be extended. For this, the extension function must be added to library classes and used in the same way as for user-defined classes.
Fun main(){
// Extension function for Int type
fun Int.abs() : Int{
return if(this < 0) -this else this
}
println((-4).abs())
println(4.abs())
}
Output:
4
4
Companion Object Extensions
In kotlin we can also define extension functions and properties for the companion object.
class MyClass {
// companion object declaration in kotlin
companion object {
fun display(){
println(“Companion object")
}
}
}
fun main(args: Array<String>) {
// invoking member function
val ob = MyClass.display()
}
Output:
companion object
As we calling the regular member function of the companion object then we can call extension function using only the class name as the qualifier.
Companion object extension example
class MyClass {
companion object {
// member function of companion object
fun display(str :String) : String{
return str
}
}
}
// extension function of companion object in kotlin
fun MyClass.Companion.abc(){
println("Extension function of companion object")
}
fun main(args: Array<String>) {
val ob = MyClass.display("Function declared in companion object")
println(ob)
// invoking the extension function
val ob2 = MyClass.abc()
}
Output:
Function declared in companion object
Extension function of companion object
Kotlin Inline Function
An inline function is declared with an inline keyword the use of inline function enhance the performance of higher order .The inline function tells the compiler to copy parameters and functions to the call site.
Why Kotlin Inline Function ?
To improve the performance inline function copy the body of the function and paste where where to call. it avoid creating of instance. So basically an inline function is just a word which we had before the function so let’s take a simple example
Example without Inline function
fun main(){
calculatetime { loop(10000) }
}
fun loop(n:Long) {
for (i in i..n)
{
}
}
fun calculatetime(fn:()->Unit)
{
val start =System.currentTimeMillis()
fn()
val end=System.currentTimeMillis()
println("Time taken ${end-start} ms")
}
Bytecode
To check the bytecode goto Tools -> Kotlin -> Show Kotlin Bytecode. Then, decompile to get this bytecode.
Without the use of the inline keyword, it will create instance of function after that it will occupied memory hence performance is decreased .
With the use of Inline keyword
fun main(){
calculatetime { loop(10000) }
}
fun loop(n:Long) {
for (i in i..n)
{
}
}
inline fun calculatetime(fn:()->Unit)
{
val start =System.currentTimeMillis()
fn()
val end=System.currentTimeMillis()
println("Time taken ${end-start} ms")
}
Bytecode
With the use of the inline keyword, it will copy the body of function and paste where to call it it avoid to create instance hence improve performance because instances is not created so memory is not occupied .
Note
If i am making one local function here named as show that it is perfectly ok but I’m adding an inline keyword to it then it is not because it says that inline function is not applicable for local functions it is only applicable for global function.
Non-Local control Flow
In Kotlin, Kotlin compiler does not allow us to return from a lambda expression. So by using the inline keyword, by itself we can return from the lambda expression and can exit the function in which inlined function is called.
Example:-
var lambdaExp = {
println("Lambda expression")
return
}
//it will give an error
fun main(args: Array<String>) {
lambdaExp()
}
Output:
Error:(4, 5) Kotlin: 'return' is not allowed here
Another example
var lambdas = { println("Lambda expression")}
fun main(args: Array<String>) {
lambdas()
}
Output:
Lambda expression
Crossinline keyword
In the above program, return in lambda will exits the inline function. So we use crossinline keyword to stop returning from the lambda expression. It will simply throw a compiler error if it sees any return statement in the Lambda expression.
Example:-
fun main(args: Array<String>){
println("Main function starts")
inlinedfunction({
println("Lambda expression 1")
return }, // It will give compiler error
{ println("Lambda expression 2")} )
println("Main function ends")
}
inline fun inlinedfunction( crossinline lmbdfucn1: () -> Unit, lmbdfucn2: () ->Unit) {
lmbdfucn1()
lmbdfucn2()
}
Output:
Error:(6, 9) Kotlin: 'return' is not allowed here
Noinline
In Kotlin, we use noinline keyword if we want only some of the lambdas passed to an inline function as to be inlined.
fun main(args: Array<String>){
println("Main function starts")
inlinedFunciton({ println("Lambda expression 1")
return }, // It does not compiler time error
{ println("Lambda expression 2")
return } ) // It gives compiler error
println("Main function ends")
}
inline fun inlinedFunction( lmbd1: () -> Unit, noinline lmbd2: () -> Unit ) {
lmbd1()
lmbd2()
}
Output:
Error:(11, 13) Kotlin: 'return' is not allowed here
Reified Type Parameters
Sometimes during the call we need to access the type of parameter passed. We have to simply the pass of the parameter at the function calling time and can retrieve the type of the parameter using a reified modifier.
fun main(args: Array<String>) {
genericFunc<String>()
}
inline fun <reified T> genericFunc() {
print(T::class)
}
Output:
class kotlin.String