Skip to main content

Kotlin: Higher order functions, Lambdas and Extension methods

Photo by Aaron Burden
“Truth can only be found in one place: the code.”
―Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship

Happy winter, how are you?. This post is continuation of Kotlin series. If you haven't read my introductory post about Kotlin then I'll recommend you reading previous post before continuing with this one.

Kotlin is a modern language. I've been working with kotlin for past few months now and I just love it. In todays post I'll talk about three features of kotlin viz. Higher Order Functions, Lambdas and Extension methods. This post also contains working code showing of each of these features. You are free to copy the code and experiment with it. If you haven't already setup kotlin on your system then you can run code using kotlin online playground.

Higher order functions

Higher order function are gist of modern functional programming languages. They treat functions as first class citizens of language in simple terms, Functions can be assigned to variables, passed to another functions as argument, can be returned from another functions and can be defined without need of wrapping them in top class unlike Java. This simple idea makes whole lot of different between non-functional languages such as Java (prior to version 1.8), C++ std11 and C. It makes code easier to read and safe (functions can be made almost side-effect safe) for threading environments. Let's see an example in kotlin.

package com.dav.vendator;
//Author: Dav Vendator
/*
Code for Kotlin: Higher Order Functions, Lambdas and Extension methods
posted at: https://streamofbytes.blogspot.com
*/
fun simpleFun() = println("Hello World")
fun returnFun(mul: Int): (arg: Int) -> Int{
return fun (arg: Int) = arg * mul
}
//typealias is like typedef in C/C++
typealias stringPredicate = (str: String) -> Boolean
//Filter list based on predicate
fun takeFun(pred: stringPredicate, list: ArrayList<String>): ArrayList<String>{
return ArrayList(list.filter { pred(it) })
}
fun main(){
simpleFun()
val newFun = returnFun(23)
println("${2} mutliplied by ${23} is ${newFun(2)}")
val filteredList = takeFun({
it.endsWith("php")
}, arrayListOf("https://helloworld.aspx", "https://streamofbytes.php", "1234"))
println("All the url's ending with *.php ${filteredList}")
}

Cool eh!, you might be asking Kotlin compiles to Java(ver 1.5 or ver 1.8 depending upon compiler configuration) and Java doesn't support them natively then how it all works under the hood?. Well to start with all the naked functions (functions without wrapper class not clothes) are placed inside a global utility class as static methods. And functions that are returned from another functions or passed as arguments to them are actually wrapped in functors (function+object C++ terminology). Tip: you can always see byte code generated by kotlin compiler which actually is pure Java code with some metadata.

Extension methods

Have you ever experienced the pain of repeating few lines of code again and again to do something that otherwise should have to come with class that came with standard library of language or from third party developer. Often number of lines of code are small enough that makes whole effort of extending the whole class and adding code into it a waste of time or source code of class is not available for you to access it. This happens very often in languages like Java. An old solution for this problem is to add a global method in utility which takes object of the required class as receiver and applies appropriate operation. Or if you are working in Koltin you can use extension methods. Let's first see an example then I'll explain what going on here.

package com.dav.vendator
import java.text.SimpleDateFormat
import java.util.*
//Author: Dav Vendator
/*
Code for Kotlin: Higher Order Functions, Lambdas and Extension methods
posted at: https://streamofbytes.blogspot.com
*/
//Without extension method
//@throws java.text.ParseException
//if you rename toDateMethod to toDate it will cause error because
//all extension methods get converted to java methods with signature as followed
//ExtensionMethodName(receiver: [RECEIVER_CLASS], arguments: [Object])
//hence the name
fun toDateMethod(receiver: String, pattern: String): Date {
val format = SimpleDateFormat(pattern, Locale.getDefault())
return format.parse(receiver)
}
//With extension method
//syntax: fun ClassName.extensionMethodName(arg)
fun String.toDate(pattern: String): Date{
return SimpleDateFormat(pattern,Locale.getDefault()).parse(this)
}
fun main(){
val pattern = "yyyy-dd-MM hh:mm a"
println("Date object : ${toDateMethod("2018-12-11 12:12 am", pattern)}")
//Much cooler
println("Date object: ${"2018-12-11 12:12 am".toDate(pattern)}")
}

In the code, you can see both approaches implemented, function toDateMethod is how I would've handled the issue in language other than kotlin. I've also included this method to show you the underlying implementation of kotlin extension methods. What kotlin does is that for every extension method it generate methods with signature (receiver, arg...) where receiving object is object over which the extension method is to be applied. Extension method hence is a syntactic sugar hiding the dirty parts beneath. Now let's move on to the last one i.e Lambdas.

Lambdas

Lambdas are like anonymous functions, they have no name, can be assigned to a variable to be used later and can be passed to another functions. If you have little experience with GUI programming then you would already have tasted the pain of writing large boiler plate code task for task as trivial as adding click listener on a button. Lambda comes in handy in these kind of cases. Best example of this is Android Framework(obviously). Google realized the pain of programmers who have to write large amount of unnecessary code in Java (ver 1.5) to get things done and hence they added kotlin support. Let's see an example of Lambdas in action.

package com.dav.vendator;
//Author: Dav Vendator
/*
Code for Kotlin: Higher Order Functions, Lambdas and Extension methods
posted at: https://streamofbytes.blogspot.com
*/
fun main(){
//Creates a Button object
val btn: Button = Button("AddUser")
//same as anonymous object of interface in Java language
btn.setListener(object : ClickListener{
override fun onClick() {
println("Called simple Listener")
}
})
//same as btn.setLambda({println("Called Lambda Listener")})
btn.setLambdaListener{
println("Called Lambda Listener.")
}
btn.performClick()
}
view raw lambdaMain.kt hosted with ❤ by GitHub
package com.dav.vendator
//A dummy button class
//Default constructor
//buttonName is available throughout the class as if it were a field variable
//this behaviour is because of val keyword before buttonName
class Button(val buttonName: String){
//lateinit keyword indicates the compiler, initialization of variable is delayed
private lateinit var onClickListener: ClickListener
//A variable hodling reference of function [see higherorder function]
private lateinit var mLambdaListener: () -> Unit
fun setListener(onClickListener: ClickListener){
this.onClickListener = onClickListener
}
fun setLambdaListener(listener: () -> Unit){
mLambdaListener = listener
}
fun performClick(){
try{
onClickListener.onClick()
mLambdaListener()
}catch (e: UninitializedPropertyAccessException){
// println("Error: ${this.buttonName} No listener to notify to.")
}
}
}
package com.dav.vendator
//A simple interface in kotlin
interface ClickListener {
fun onClick()
}

In code, I have simply tried simulating a basic scenario of listening for click event from button. Imagine having more than 100 components to listen to for more than 1000 different event. That's hell a lot amount of code. Kotlin's compiler does the dirty job for you while providing elegant and readable syntactic sugar.


Well, that's all for this one. If you encountered errors or have questions regarding kotlin or have accidentally launched a Nuclear Missile (I am serious this time) just comment here and I'll try my best to help you out. Comment if you liked it; Follow if you loved it(show some love naa ❣). Have a nice time.

Comments

Popular posts from this blog

Coding conventions part 1 : Naming Things

“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.” —John Woods At some point in the life of every programmer comes a time, when he/she realize that the way he/she organize code sucks(I have this moment like every day). And it's time to change few things and start caring about the organization and readability of code. Code organization is crucial part of software development. Because software is not something which is developed from scratch again and again (as it will cost both time and money) but is updated and maintained for as long as it is possible to do so(this is why we have code re usability thingy). Programmer of special breed that is “Software Maintainer” is assigned this task. These are some of the most calm people in the industry because most of their salary is spent on Anger Management (May God bless them). If a code is poorly organized then more time is spent in refactoring it th...

Kotlin : An introduction

Photo by wu yi “A language that doesn't affect the way you think about programming is not worth knowing.” ―Alan J. Perlis World was nice and there was only assembly(“real programmers code in assembly”) but then one day out of blue he (hey! don't look at me like that I too don't know his name) came and said let there be compilers and interpreters(line by line) that will translate languages easy to read(uh! nah not really) and write into assembly to make programming fun again and that gave birth to an era of exotic new programming languages called procedural programming languages. Procedural programming languages were doing fine but after some time lot's of programmer started loosing their objects because of stateless functions which globally caused chaos. Seeing all this made him angry. So he said, “Procedural languages, I command you to treat everything as an ‘Object’ which will have it's own properties(attributes) and behavior(methods)”. They respond...