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

You may also like...

0 Comments

No Comment.