Scope Functions

What is Scope Function

execute a block of code within the context of an object.

 

There are five of them:

let, run, with, apply, and also.

Why Scope Function?

val alice = Person("Alice", 20, "Amsterdam")
println(alice)
alice.moveTo("London")
alice.incrementAge()
println(alice)
Person("Alice", 20, "Amsterdam").run {
  println(this)
  moveTo("London")
  incrementAge()
  println(this)
}
  • Is extension function

  • Object reference

  • Return value

Extension function

Person("Adam").apply {
    age = 32
    city = "London"        
}
run {
    val digits = "0-9"
    val hexDigits = "A-Fa-f"
    val sign = "+-"

    Regex("[$sign]?[$digits$hexDigits]+")
}

Object Reference

  • this

  • it

Object Reference

Person("Adam").apply { 
    age = 20                
    city = "London"
}
Random.nextInt(100).also {
	writeToLog("getRandomInt() generated value $it")
}

Return Value

  • context object

  • lambda result

Return Value

fun getRandomInt(): Int {
    return Random.nextInt(100).also {
        writeToLog("getRandomInt() generated value $it")
    }
}
val countEndsWithE = numbers.run { 
    add("four")
    add("five")
    count { it.endsWith("e") }
}

Compare Table

Function Object reference Return value Is extension function
let it Lambda result Yes
run this Lambda result Yes
run - Lambda result No: called without the context object
with this Lambda result No: takes the context object as an argument.
apply this Context object Yes
also it Context object Yes

Scenario

  • Executing a lambda on non-null objects: let

  • Introducing an expression as a variable in local scope: let

  • Object configuration: apply

  • Object configuration and computing the result: run

  • Running statements where an expression is required: non-extension run

  • Additional effects: also

  • Grouping function calls on an object: with

let

  • Executing a lambda on non-null objects

  • Introducing an expression as a variable in local scope

  • for null checks

let sample

var str = "Hello World"
str.let { println("$it!!") }
fragmentManager?.let {
	tagFragment.show(it, "")
}

run

  • Object configuration and computing the result: run

  • run expression can change the outer property.

run sample

var tutorial = "This is Kotlin Tutorial"
println(tutorial) //This is Kotlin Tutorial
tutorial = run {
  val tutorial = "This is run function"
  tutorial
}
println(tutorial) //This is run function
webView.settings.run {
  javaScriptEnabled = true
  domStorageEnabled = true
  userAgentString = "mobile_app_webview"
  webView
}

with

with is used to change instance properties without the need to call dot operator over the reference every time.

with sample

data class Person(var name: String, var tutorial : String)
var person = Person("Anupam", "Kotlin")

with(person){
  name = "No Name"
  tutorial = "Kotlin tutorials"
}

apply

 It runs on the object reference (also known as receiver) into the expression and returns the object reference on completion.

apply sample

val p = person.apply{
  name = nameInput.text.toString()
  phone = phoneInput.text.toString()
  id = idInput.text.toString()
  sex = sexInput.text.toString()
}

also

Use also for additional actions, such as logging or printing debug information.

also sample

val numbers = mutableListOf("one", "two", "three")
numbers
    .also { println("The list elements before adding new one: $it") }
    .add("four")
    .also { println("The list elements after adding new one: $it") }

Conclusion

  • let for null check.

  • run for configuration.

  • with for change instance properties.

  • apply for register.

  • also for log information.

 

Thank you.

Made with Slides.com