New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using scope functions apply/with/run/also/let #35

Open
cypressious opened this Issue Feb 20, 2017 · 6 comments

Comments

Projects
None yet
5 participants
@cypressious

cypressious commented Feb 20, 2017

apply

Use apply for initialization:

val foo = createBar().apply {
    property = value
    init()
}

also

Use also over apply if the receiver is used for anything other than setting properties or function calls on it:

class Baz {
    var currentBar: Bar?
    val observable: Observable

    val foo = createBar().also {
        currentBar = it
        observable.registerCallback(it)
    }
}

Prefer also over apply if there already are multiple receivers in scope, especially if you make calls on any outer receivers:

class Foo {
    fun Bar.baz() {
        val stuff = callSomething().also {
            it.init()
            this@baz.registerCallback(it)
        }
    }
}

apply/with/run

Prefer apply/run over with if the receiver is nullable.

getNullable()?.run {
    init()
}

getNullable()?.apply {
    init()
}

Prefer run/with over apply if the returned value is not used

view.run {
    textView.text = "Hello World"
    progressBar.init()
}

with(view) {
    textView.text = "Hello World"
    progressBar.init()
}

Choose one of the above and use it consistently.

let

Prefer let over run in method chains that transform the receiver

val baz: Baz = foo.let { createBar(it) }.convertBarToBaz()
// or with function references
val baz: Baz = foo.let(::createBar).convertBarToBaz()
@voddan

This comment has been minimized.

Show comment
Hide comment
@voddan

voddan Feb 22, 2017

I use with over run if the object in question is a local variable or a short expression:

with(view) {
    textView.text = "Hello World"
    progressBar.init()
}

On the other hand, I use run in the end of a long call chain:

MyApp.defaultActivity.getActiveView().view.run {
    textView.text = "Hello World"
    progressBar.init()
}

voddan commented Feb 22, 2017

I use with over run if the object in question is a local variable or a short expression:

with(view) {
    textView.text = "Hello World"
    progressBar.init()
}

On the other hand, I use run in the end of a long call chain:

MyApp.defaultActivity.getActiveView().view.run {
    textView.text = "Hello World"
    progressBar.init()
}
@MarcinMoskala

This comment has been minimized.

Show comment
Hide comment
@MarcinMoskala

MarcinMoskala Jul 25, 2017

@cypressious Why you prefer run over apply if the returned value is not used? run is also returning value - the result of function literal. The same with with, but for this one, I also feel intuitively that it should be used this way.

MarcinMoskala commented Jul 25, 2017

@cypressious Why you prefer run over apply if the returned value is not used? run is also returning value - the result of function literal. The same with with, but for this one, I also feel intuitively that it should be used this way.

@MarcinMoskala

This comment has been minimized.

Show comment
Hide comment
@MarcinMoskala

MarcinMoskala Jul 25, 2017

I use let when I just need to unpack nullable read-write property (when smart-casting is not working):

var text: String? = null
fun showText() {
    text?.let { text -> 
        println(text) 
    }
}

I often see let used this way.

MarcinMoskala commented Jul 25, 2017

I use let when I just need to unpack nullable read-write property (when smart-casting is not working):

var text: String? = null
fun showText() {
    text?.let { text -> 
        println(text) 
    }
}

I often see let used this way.

@cypressious

This comment has been minimized.

Show comment
Hide comment
@cypressious

cypressious Aug 1, 2017

@MarcinMoskala it's just to differentiate. I use apply when I need to the receiver as the return value, otherwise I don't use it.

cypressious commented Aug 1, 2017

@MarcinMoskala it's just to differentiate. I use apply when I need to the receiver as the return value, otherwise I don't use it.

@kingsleyadio

This comment has been minimized.

Show comment
Hide comment
@kingsleyadio

kingsleyadio Aug 4, 2017

Another good use of with is for executing a lambda in the context of a casted object:

with(activity as MyActivity) {
  myActivitymethod()
  ...
}

kingsleyadio commented Aug 4, 2017

Another good use of with is for executing a lambda in the context of a casted object:

with(activity as MyActivity) {
  myActivitymethod()
  ...
}
@tlazenka

This comment has been minimized.

Show comment
Hide comment
@tlazenka

tlazenka Aug 29, 2017

Using also for a "singleton with parameter" (from Google's architecture components sample code):

class UsersDatabase : RoomDatabase() {

    companion object {

        @Volatile private var INSTANCE: UsersDatabase? = null

        fun getInstance(context: Context): UsersDatabase =
                INSTANCE ?: synchronized(this) {
                    INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
                }

        private fun buildDatabase(context: Context) =
                Room.databaseBuilder(context.applicationContext,
                        UsersDatabase::class.java, "Sample.db")
                        .build()
    }
}

https://github.com/googlesamples/android-architecture-components/blob/master/BasicRxJavaSampleKotlin/app/src/main/java/com/example/android/observability/persistence/UsersDatabase.kt

tlazenka commented Aug 29, 2017

Using also for a "singleton with parameter" (from Google's architecture components sample code):

class UsersDatabase : RoomDatabase() {

    companion object {

        @Volatile private var INSTANCE: UsersDatabase? = null

        fun getInstance(context: Context): UsersDatabase =
                INSTANCE ?: synchronized(this) {
                    INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
                }

        private fun buildDatabase(context: Context) =
                Room.databaseBuilder(context.applicationContext,
                        UsersDatabase::class.java, "Sample.db")
                        .build()
    }
}

https://github.com/googlesamples/android-architecture-components/blob/master/BasicRxJavaSampleKotlin/app/src/main/java/com/example/android/observability/persistence/UsersDatabase.kt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment