Upgrade to Pro — share decks privately, control downloads, hide ads and more …

7. Lambda With Receiver [kotlin-workshop]

7. Lambda With Receiver [kotlin-workshop]

Part of https://github.com/jetBrains/kotlin-workshop.

Covers:
- the concept of lambda with receiver
- DSLs examples
- with/apply/also/let/run functions

Svetlana Isakova

November 01, 2017
Tweet

More Decks by Svetlana Isakova

Other Decks in Programming

Transcript

  1. val sb = StringBuilder()
 with (sb) {
 appendln("Alphabet: ")
 for

    (c in 'a'..'z') {
 append(c)
 } toString()
 } The with function with is a function val sb = StringBuilder()
 sb.appendln("Alphabet: ")
 for (c in 'a'..'z') {
 sb.append(c)
 }
 sb.toString()

  2. lambda is its second argument val sb = StringBuilder()
 with

    (sb) {
 this.appendln(“Alphabet: ")
 for (c in 'a'..'z') {
 this.append(c)
 } this.toString()
 } val sb = StringBuilder()
 with (sb, { ->
 this.appendln(“Alphabet: ")
 for (c in 'a'..'z') {
 this.append(c)
 } this.toString()
 }) lambda is its second argument Lambda with receiver with is a function this is an implicit receiver in the lambda val sb = StringBuilder()
 with (sb) {
 appendln("Alphabet: ")
 for (c in 'a'..'z') {
 append(c)
 } toString()
 } this can be omitted
  3. Lambda with receiver val sb = StringBuilder()
 with (sb) {


    appendln("Alphabet: ")
 for (c in 'a'..'z') {
 this.append(c)
 } } lambda with implicit this
  4. regular function regular lambda extension function lambda with receiver fun

    String.lastChar() = this.get(this.length - 1) buildString { this.append("...") } Extension function vs lambda with receiver
  5. regular function regular lambda extension function lambda with receiver Lambda

    vs lambda with receiver val isEven: (Int) -> Boolean = { it % 2 == 0 } val isOdd: Int.() -> Boolean = { this % 2 == 1 } isEven(0) 1.isOdd() calling as regular function calling as extension function
  6. val s: String = buildString {
 appendln("Alphabet: ")
 for (c

    in 'a'..'z') {
 append(c)
 }
 } Another example: buildString lambda with receiver
  7. buildString { this.append("...") } inline fun buildString( builderAction: StringBuilder.() ->

    Unit ): String { val stringBuilder = StringBuilder() ... return stringBuilder.toString() } The buildString function Creates a StringBuilder Calls the specified actions on a stringBuilder Returns String as a result stringBuilder.builderAction()
  8. with (sb) {
 appendln("Alphabet: ")
 ...
 } inline fun <T,

    R> with( receiver: T, block: T.() -> R ): R = receiver.block() The with function declaration
  9. val db: SQLiteDatabase = … db.beginTransaction()
 try {
 db.delete("users", "first_name

    = ?", arrayOf("Jake"))
 db.setTransactionSuccessful()
 } finally {
 db.endTransaction()
 } db.inTransaction {
 delete("users", "first_name = ?", arrayOf("Jake"))
 } Avoiding Duplication
  10. db.beginTransaction()
 try {
 db.delete("users", "first_name = ?", arrayOf("Jake"))
 db.setTransactionSuccessful()
 }

    finally {
 db.endTransaction()
 } db.inTransaction {
 delete("users", "first_name = ?", arrayOf("Jake"))
 } Inline functions is declared as inline function generated bytecode is similar to
  11. html {
 table {
 for (product in products) {
 tr

    {
 td { text(product.description) }
 td { text(product.price) }
 td { text(product.popularity) }
 }
 }
 }
 } HTML Builders lambdas with receiver
  12. Alerts fun Activity.showAreYouSureAlert(process: () -> Unit) {
 alert(title = "Are

    you sure?",
 message = "Are you really sure?") {
 positiveButton("Yes") { process() }
 negativeButton("No") { }
 }.show()
 } Are you sure? Are you really sure? No Yes
  13. customView {
 verticalLayout {
 val email = editText {
 hint

    = "Email"
 }
 
 val password = editText {
 hint = "Password"
 transformationMethod = PasswordTransformationMethod.getInstance()
 }
 
 positiveButton("Log In") {
 logIn(email.text, password.text)
 }
 }
 } Password Log In Email Custom layouts
  14. plugins { application kotlin("jvm") version "1.1.51" } application { mainClassName

    = "samples.HelloWorldKt" } dependencies { compile(kotlin("stdlib")) } repositories { jcenter() } Gradle Build Script in Kotlin
  15. More useful library functions inline fun <T, R> with(receiver: T,

    block: T.() -> R): R = receiver.block() inline fun <T, R> T.run(block: T.() -> R): R = block() inline fun <T, R> T.let(block: (T) -> R): R = block(this) inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this } inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }
  16. with with (window) { width = 300 height = 200

    isVisible = true } inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
  17. run: like with, but extension val windowOrNull = windowById["main"] windowOrNull?.run

    { width = 300 height = 200 isVisible = true } inline fun <T, R> T.run(block: T.() -> R): R = block()
  18. run: like with, but extension windowById["main"]?.run { width = 300

    height = 200 isVisible = true } inline fun <T, R> T.run(block: T.() -> R): R = block()
  19. apply: returns receiver as a result val mainWindow = windowById["main"]?.apply

    { width = 300 height = 200 isVisible = true } ?: return inline fun <T> T.apply(block: T.() -> Unit): T { this.block(); return this }
  20. also: regular argument instead of this inline fun <T> T.also(block:

    (T) -> Unit): T { block(this); return this } windowById["main"]?.apply { width = 300 height = 200 isVisible = true }?.also { showWindow(it) }
  21. { .. this .. } { .. it .. }

    return result of lambda run let return receiver apply also receiver.apply { this.actions() } receiver.also { moreActions(it) }