Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using Kotlin Scope Functions

DZone's Guide to

Using Kotlin Scope Functions

Want to learn more about using Kotlin scope functions? Check out this post to learn more when you should consider refactoring your code and using scope functions

· Java Zone ·
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

Do we really need yet another blog post on Kotlin scope functions?

As a matter of fact, I think we do! While there are many posts looking at this special function in Kotlin, I found none on how to pick up the correct function and when you should consider refactoring your code into using one of them.

I’ve tried to make it clear with the following diagram:

Use this means we are going to (mostly) call methods on a single object, the reference to the object is this.

Pass it means we need to pass the object to other methods/functions, the reference to the object is it.

Result means we will have a result value from the block and we need to return it.

Side-effects means we don’t expect a result but we want to call for some methods that return Unit (a.k.a. void) and maybe combine them in Fluent Interface style.

So, if you are wondering how to simplify code where an object (the target object) is used multiple times, you should ask yourself two questions:

Do I need to call methods on this object, or do I need to pass it as an argument to other methods/function?
Do I have a result at the end? Or, am I only changing the state?

 apply is useful if you need to call several methods on an object without caring for their return, like setters. Like the other three Extended Functions, if the target object is null, the block won’t be called, and inside the block, the object is always of a non-nullable type. For example:

fun updateItem(itemId: String, newName: String, newPrice: Double) = itemsMap.get(itemId)?.apply { 
    enabled = true
    desc = newName
    price = newPrice
}


with works almost exactly as apply ; the only difference is that if the object of a nullable type, then it will call the block anyway, passing the object as nullable. I use it only when there is a long block of code with some methods calling on a specific object, particularly if the var has a long name. For example:

// ... long method
val total = with(ridicurioslyLongNameOfFrameworkSingleton){ 
   setSomething(a)
   setSomethingElse(b)
// do other things...
   getTotal()
}
// ...


let is probably the most used, at least by me. It is particularly useful together with the question mark to obtain a result if a value is not null. You should consider removing any code that resemblesif (obj == null) {...} and use let or another scope function. For example:

fun fullName(firstName: String, middleName: String?, familyName: String) = middleName?.let{ 
   "$firstName ${it.first()}. $familyName"
} ?: "$firstName $familyName"


 run is useful if, at the end, calling a few methods on the object and one returns something else. For example:

fun cartTotal(cart: Cart, items: List<CartItem>) = cart.run{ 
   items.foreach{addItem(it)}
   calcTotal()
}


also is useful if you have a value that you need to return, but before returning, you also need to use it to do something else. For example:

fun createUser(userName: Stirng): Int =
    myAtomicInt.getAndIncrement().also { users.put(it, userName) }


As reference these are the signatures:

public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
public inline fun <T, R> T.run(block: T.() -> R): R = block()
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }


“I don’t see any advantage in using them, it’s just messing things around,” is a quite common objection that I heard when I showing code to people not familiar to Kotlin.

The lesser advantage of using a scope function is to save some lines of code. The greater advantage is to avoid temporary variables.

Temporary variables are usually a bad idea in functional programming, and they are a source of small bugs when you confuse them or you copy and paste some code around (which of course none of us ever do!).

In functional programming, style is also better (in the sense of transmitting a more clear intention) to use the single expression declaration form (that is fun f = …) for functions, and scope functions make it easier.

If you enjoyed this post, please be sure to give it a like! Thanks.

Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat

Topics:
java ,kotlin ,functions ,scope functions

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}