Do with
and run
have the same functionality with only different syntax, or is there any major differences between with
and run
?
Which is the proper way?
adapter.run {
notifyDataSetChanged()
if (activityDetails.isEmpty())
emptyText.visibility = View.VISIBLE
else
emptyText.visibility = View.GONE
}
with(adapter){
notifyDataSetChanged()
if (activityDetails.isEmpty())
emptyText.visibility = View.VISIBLE
else
emptyText.visibility = View.GONE
}
They have only syntactic difference, run
is an extension function while with
is not. Here are the definitions (in kotlin-sdlib:1.0.3
):
public inline fun <T, R> T.run(block: T.() -> R): R = block() // equivalent to this.block()
public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
Since run
is an extension function, it has one more implicit argument of type T
, so the argument types are the same. The bodies of the functions are also effectively the same.
Their performance should also be equivalent since both are inline
functions: the resulting bytecode should only contain the inlined block
body.
The differences in the functions usage are all caused by the fact that run
is an extension.
First, run
is suitable for calls chaining:
foo.run { bar }.run { baz }
Second, and more important, if a declared variable type has run
function with the same signature, it will be called instead of the extension. And run
can be shadowed by another extension. This is how extensions are resolved. Example:
class MyClass {
fun <R> run(blockIgnored: MyClass.() -> R): Nothing = throw RuntimeException()
}
"abcdefg".run { println("x") } // prints "x"
MyClass().run { println("x") } // throws RuntimeException
(MyClass() as Any).run { println("x") } // prints "x"
In normal case, they are pretty similar, but for a nullable variable, it's better to use T.run()
E.g. if webview.settings
is nullable, below would show the distinct
with(webview.settings) {
this?.javaScriptEnabled = true
this?.databaseEnabled = true
}
// similarly
webview.settings?.run {
javaScriptEnabled = true
databaseEnabled = true
}