Entrepreneur. Creator of Groovy++ Alex is a DZone Zone Leader and has posted 31 posts at DZone. You can read more from them at their website. View Full User Profile

Kotlin in action: few tricks for every day use

06.24.2012
| 14106 views |
  • submit to reddit

In this post I would like to show several tricks, which I found to be very useful while develoiping small examples with the Kotlin programming language.

Extension functions

Extension functions is amazing ability to "add methods" to existing classes, which you do not own and can not modify. Here is my favorite sample from Kotlin standard library.

public inline fun Executor.execute(action: ()->Unit) {
    execute(object: Runnable {
public override fun run() {
action()
}
}) }

We extend interface Executor defined in JDK with ability to execute not only Runnable but any given function literal like in the following example.

executor execute {
   println "I am function wrapped by Runnable and executed by Executor"
} 

Please notice that in extension function we can use methods of the class we extend without mentioning this keyword. In our example we call Executor.execute(Runnable) 

invoke-function convention

By Kotlin convention any object which have method invoke can be called as if it was function. Our example above can be rewritten in even more interesting form.

public inline fun Executor.invoke(action: ()->Unit) {
    execute(runnable(action))
}

executor {
   println "I am function wrapped by Runnable and executed by Executor"
}

Default arguments

Function parameters may have default values, which are used when a corresponding argument is omitted. This allows to reduce the number of overloads, compared to Java.

In the following example we have function, which creates fixed thread pool, execute given action and shutdown the pool. 

fun withFixedThreadPool(threadNum: Int = Runtime.getRuntime()!!.availableProcessors(), action: (Executor)->Unit) {
    val myExecutor = Executors.newFixedThreadPool(threadNum)!!
    try {
        action(myExecutor)
    }
    finally {
        myExecutor.shutdown()
    }
}

We can either provide number of thread to create explicitly or use default value equal to number of available processors like in the example below.

    withFixedThreadPool { executor ->
        processCraigList(executor) { jobUrl, jobText ->
            println("$jobUrl loaded")
        }
    }

Named arguments

When a function has many parameters (and many of them have defaults), it is very convenient to see parameter names at the call site. I love the following function from Kotlin standard library

public fun thread(start: Boolean = true, daemon: Boolean = false, contextClassLoader: ClassLoader? = null, name: String? = null, priority: Int = -1, block: ()->Unit) : Thread {
    val thread = object: Thread() {
        public override fun run() {
            block()
        }
    }
    if(daemon)
        thread.setDaemon(true)
    if(priority > 0)
        thread.setPriority(priority)
    if(name != null)
        thread.setName(name)
    if(contextClassLoader != null)
        thread.setContextClassLoader(contextClassLoader)
    if(start)
        thread.start()
    return thread
}

It allows to create and fully customize thread with function literal. For example code snippet below will create and start daemon thread named "log poller"

thread(daemon = true, name = "log poller") {
   //  ..... whatever the thread has to do
}

Wrapping function literal

Wrapping function literal is very convinient construction when you need to localize some variable in the scope. Let us consider following example

        var i = -100
        val indexUrlIterator = iterate<String> {
            i += 100
            if(i == 1000) null else "http://newyork.craigslist.org/jjj/index${if(i == 0) "" else i}.html"
        }

We use function iterate from Kotlin standard library. It returns an iterator which invokes the function to calculate the next value on each iteration until the function returns null.

In our case iteration requires state to keep between invocations. The state is represented by local variable i. Unfortunately this variable still around even after iteartor created.

Here is how we can localize this variable

    val indexUrlIterator = {
        var i = -100
        iterate<String> {
            i += 100
            if(i == 1000) null else "http://newyork.craigslist.org/jjj/index${if(i == 0) "" else i}.html"
        }
    }();

What we did is we define function literal, execute it immidiately and assign result of execution to local varuiable we want to use later. You might think it is overkill for such simple example but in fact I found this pattern (widely used btw by javascript developers) to be very helpful.

That's all for for today. thank you and till next time.

 

Published at DZone with permission of its author, Alex Tkachman.
Tags: