There are quite a few blog posts (like this) on usages of the standard library functions apply
/with
/run
/also
/let
available that make it a bit easier to distingish when to actually use which of those pretty functions.
For a few weeks now, the official docs even provide guidelines on that topic finally: https://kotlinlang.org/docs/reference/coding-conventions.html#using-scope-functions-applywithrunalsolet
Nevertheless, I think it is pretty hard to memorize the function's individual use cases by the function names. I mean, for me they seem to be interchangeable, why isn't let
called run
for instance?
Any suggestions? I think the names aren't very expressive which makes it hard to see the differences at first.
I strongly recommend to read this blog in order to understand all of these scope functions.
Some keys of these blog:
Following the first letter of each, you get the acronym “LARA”.
Common use cases
With
with()
is functionally the same as the extension function version ofrun()
, so it's well-suited to the use case of Initialize and execute. More information.Adding to the @kirillRakhman answer:
A major part in the naming process was (still is) fluent reading experience in major use cases.
with
:apply
:also
:IMHO it doesn't really work with
let
well. After all, it was taken from "those scary FP languages". But I often think of it as a sort ofLet's do this!
construct. Like below you could read the code aslet's print it!
: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 WikipediaIn FP languages like Haskell you can use
let
to bind values to variables in a restricted scope like soThe equivalent (albeit overly complicated) code in Kotlin would be
The typical usage of
let
is to bind the result of some computation to a scope without "polluting" the outer scope.with
The
with
function is inspired by thewith
language construct from languages like Delphi or Visual Basic (and probably many others) whereThe equivalent Kotlin would be
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
andinit
were proposed but the nameapply
, proposed by Daniil Vodopian, ultimately won.apply
is similar towith
in that it can be used to initialize objects outside of the constructor. That's why, in my opinion,apply
might as well be namedwith
. However aswith
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 asapply
.also
also
was added to the stdlib even later thanapply
, namely in version 1.1. Again, https://youtrack.jetbrains.com/issue/KT-6903 contains the discussion. The function is basically likeapply
except that it takes a regular lambda(T) -> Unit
instead of an extension lambdaT.() -> 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
reads a bit like
Other stdlib functions whose usages read a bit like English sentences include
takeIf
andtakeUnless
which also were added in version 1.1.run
Finally, the
run
function actually has two signatures. The first onefun <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 propertyThe 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 receiverI'm not aware of any historical reasons for the naming.