Sunday 12 June 2022

Kotlin Delegation

In object-oriented programming, delegation refers to evaluating a member (property or method) of one object (the receiver) in the context of another original object (the sender). 


Delegation is a design pattern in which an object handles a request by delegating to a helper object, called the delegate. The delegate is responsible for handling the request on behalf of the original object and making the results available to the original object.  


Kotlin supports “delegation” design pattern by introducing a new keyword “by”. Using this keyword or delegation methodology, Kotlin allows the derived class to access all the implemented public methods of an interface through a specific object


Delegation should be used when:

  • Any components that behave identically, but we realize were it will have some upgradation on top of it in future point of time where we do our own logical implementation and expose the results.  For E.g. We can take an example of Analytics class, where instead of directly using the analytics method we can have our delegation and use the param to handle the screen views and event logging.
  • Place where we feel delegate would be the better than inheritance because, it doesn’t force you to define all the methods of the super class, you can use or override only the methods that really needed.  For e.g. here you can refer the code below that PaymentProcess doesn’t enforced to override the method (Kotlin), but if really needed we can override and do our implementations.
  • If we want to extend the behavior of classes that we cannot or don’t want to subclass for the below reasons For E.g. here you can see in the below code snippet Payment classes (CashPayment, UPIPayment, CardPayment) are can’t be inherited.
    • Restricted to share or disallowed to create a hierarchy (Class marked as final)
    • Planning to expose the limited or different API methods by consuming the existing code functionality and also we may add our feature update. 
    • Planned to hide the serious implementation from the calling code.


Example: This will be very simple and self-explanatory code snippet, here we are having an interface IPayment for the payment and it would track the mode of payment happens, and there would be an implementation classes CashPayment, UPIPayment, CardPayment of different mode of payment (Cash, Card and UPI).   There in PaymentProcess class the delegation will be happen through the interface.  Also the method paymentProcess in java and processPayment in Kotlin does the payment process.   

Comparatively with Java and Kotlin, In Kotlin we avoid lot of boilerplate code because of delegation using “by”, else in java we are mandatory to do the implementation of all interface method (see in this example I have used only one interface method, so if it is more than, it would be more override method in PaymentProcess.java class). 


Java Style of Delegate


Kotlin Style of Delegate:

Happy Coding :-)

Sunday 5 June 2022

SAM - Functional Interface




Almost we all of us have seen code like view.setOnClickListener { } or view.setOnLongClickListener { } in Kotlin, and when you click on it to see the source code it will show you the Java OnClickListener interface. Is it a kotlin extension? How can we call our custom listener like this? Let’s see the answer to all of these now.

This syntax is not an extension, it is SAM conversion, SAM stands for Single Abstract Method interface and it’s called also Functional interface which is an interface with only one non-default method (abstract method) and any number of default methods (non-abstract methods), for examples In the JDK we have Runnable class which has only one method called run and in Android SDK we have OnClickListener, OnLongClickListener etc..

How can we create a custom functional interface?

In Kotlin starting from Version 1.4, we can declare a functional interface in Kotlin, we need to use the fun modifier before to the interface keyword.
fun interface MyInterface {
    fun aMethod()
}
Creating a function with the functional interface as param

fun runMyInterface(fi : MyInterface) { ... }


We can pass MyInterface as an anonymous object 

runMyInterface(object : MyInterface {

    override fun aMethod() {

        println("Welcome to www.rajendhiraneasu.in")

    }

})

For functional interfaces, SAM conversion can be achieved through lambda expressions, which makes the code more concise and more readable.  Using lambda expressions can replace manually creating classes that implement functional interfaces. Through SAM conversion, Kotlin can convert any lambda expression whose signature matches the signature of a single abstract method of an interface into an instance of a class that implements the interface.  Please see the above anonymous reference with lambda expressions as below

runMyInterface ({ println("Welcome to www.rajendhiraneasu.in") })


Also, in Kotlin if your last parameter is functional interface you can move your lambda out the brackets ()

runMyInterface {

    println("Welcome to www.rajendhiraneasu.in")

}


Now you can realize that setOnClickListener { } is just because this method takes functional interface which is OnClickListener as a parameter.

Eg: Let’s see with the use case to get the Students Grade of different class levels.
 
// Class Levels
const val PRIMARY_SCHOOL = 1
const val HIGH_SCHOOL = 2

// Data Class holds the student details
data class StudentMarks(val sName: String, val classLevel: Int, val sAvg: Double) {
    fun getStudentGrade(predicate: GradePredicate) = predicate.getGrade((sAvg))
}

// Functional interface (SAM)
fun interface GradePredicate {
    fun getGrade(avg: Double): String
} 

// Grade Predicate definition as lambda 
val primarySchoolGrade = GradePredicate {
    when {
        it > 90 -> "A+"
        it > 80 -> "A"
        it > 65 -> "B"
        it > 45 -> "C"
        it > 34 -> "D"
        else -> "F"
    }
}

val highSchoolGrade = GradePredicate {
    when {
        it > 80 -> "Very Good"
        it > 60 -> "Good"
        it > 34 -> "Fair"
        else -> "Fail"
    }
}

// Lambda expression to select the grade predicate based on the class level 
val gradeSel by lazy { { classLevel: Int -> if (classLevel == PRIMARY_SCHOOL) primarySchoolGrade else highSchoolGrade } }

fun main() {
 val studentList = listOf(
        StudentMarks("Ragavan", PRIMARY_SCHOOL, 92.79),
        StudentMarks("Rajeevan", PRIMARY_SCHOOL, 65.15),
        StudentMarks("Rajeevan", PRIMARY_SCHOOL, 52.23),
        StudentMarks("Arun", HIGH_SCHOOL, 83.21),
        StudentMarks("Harish", HIGH_SCHOOL, 63.56)
    )

    println("Name || Grade")
    studentList.forEach {
        println(
            "${it.sName} ||  ${
                it.getStudentGrade(gradeSel(it.classLevel))
            }"
        )
    }
}
 
Output: