Here's an unofficial overview of how the names seem to have come to be.
let
let
is inspired by the functional programming world. According to Wikipedia
a "let" expression associates a function definition with a restricted scope
In FP languages like Haskell you can use let
to bind values to variables in a restricted scope like so
aaa = let y = 1+2
z = 4+6
in y+z
The equivalent (albeit overly complicated) code in Kotlin would be
fun aaa() = (1+2).let { y ->
(4+6).let { z ->
y + z
}
}
The typical usage of let
is to bind the result of some computation to a scope without "polluting" the outer scope.
creater.createObject().let {
if (it.isCorrect && it.shouldBeLogged) {
logger.log(it)
}
}
// `it` is out of scope here
with
The with
function is inspired by the with
language construct from languages like Delphi or Visual Basic (and probably many others) where
The with keyword is a convenience provided by Delphi for referencing
elements of a complex variable, such as a record or object.
myObject.colour := clRed;
myObject.size := 23.5;
myObject.name := 'Fred';
can be rewritten :
with myObject do
begin
colour := clRed;
size := 23.5;
name := 'Fred';
end;
The equivalent Kotlin would be
with(myObject) {
color = clRed
size = 23.5
name = "Fred"
}
apply
apply
was added to the stdlib relatively late in the milestone phase (M13). You can see this question from 2015 where a user asks for exactly such a function and even suggests the later to-be-used name "apply".
In the issues https://youtrack.jetbrains.com/issue/KT-6903 and https://youtrack.jetbrains.com/issue/KT-6094 you can see discussions of the naming. Alternatives like build
and init
were proposed but the name apply
, proposed by Daniil Vodopian, ultimately won.
apply
is similar to with
in that it can be used to initialize objects outside of the constructor. That's why, in my opinion, apply
might as well be named with
. However as with
was added to the stdlib first, the Kotlin devs decided against breaking existing code and added it under a different name.
Ironically, the language Xtend provides the so-called with-operator =>
which basically does the same as apply
.
also
also
was added to the stdlib even later than apply
, namely in version 1.1. Again, https://youtrack.jetbrains.com/issue/KT-6903 contains the discussion. The function is basically like apply
except that it takes a regular lambda (T) -> Unit
instead of an extension lambda T.() -> Unit
.
Among the proposed names were "applyIt", "applyLet", "on", "tap", "touch", "peek", "make". But "also" won as it doesn't collide with any keywords or other stdlib functions and its usages (more or less) read like English sentences.
Example
val object = creater.createObject().also { it.initiliaze() }
reads a bit like
Creater, create the object and also initialize it!
Other stdlib functions whose usages read a bit like English sentences include takeIf
and takeUnless
which also were added in version 1.1.
run
Finally, the run
function actually has two signatures. The first one fun <R> run(block: () -> R): R
simply takes a lambda and runs it. It is mostly used for assigning the result of a lambda expression to a top-level property
val logger = run {
val name = System.property("logger_name")
Logger.create(name)
}
The second signature fun <T, R> T.run(block: T.() -> R): R
is an extension function which takes an extension lambda as parameter and seems to also be named "run" for symmetry reasons. It also "runs" a lambda but in the context of an extension receiver
val result = myObject.run {
intitialize()
computeResult()
}
I'm not aware of any historical reasons for the naming.
let
. Learned it on the spot. Same withwith
or 'also'. Once you know they exist, you'll get into the cases when you know there is something but you don't remember which is. Several trips to the docs will ensure you'll know them in the future. At least this is how I'm doing it – Illuminance