##### ##
###### /###
/# / / ###
/ / / ### ##
/ / ## ##
## ## ## /### ## ### #### /## ### /###
## ## ## / ### / ## ### ### / / ### ###/ #### /
/### ## / / ###/ ## ### ###/ / ### ## ###/
/ ### ## / ## ## ## ## ## ## ### ##
## ######/ ## ## ## ## ## ######## ##
## ###### ## ## ## ## ## ####### ##
## ## ## ## ## ## ## ## ##
## ## ## ## ## /# / #### / ##
## ## ###### ######/ ######/ ######/ ###
## ## ## #### ##### ##### ##### ###
### # /
### /
#####/
###
/##
#/ ###
## ###
##
##
/### ######
/ ### / #####
/ ###/ ##
## ## ##
## ## ##
## ## ##
## ## ##
## ## ##
###### ##
#### ##
###
# ### #
### ## ###
# ## #
##
### ### /### ## ### ### /### /##
### ###/ #### / ## ### ###/ #### / / ###
## ## ###/ ## ## ## ###/ / ###
## ## ## ## ## ## ## ## ###
## ## ## ## ## ## ## ########
## ## ## ## ## ## ## #######
## ## ## ## ## ## ## ##
## ## ## ## ## ## ## #### /
### / ### ### ### / ### / ### ### ######/
##/ ### ### ##/ ##/ ### ### #####
BlrKotlin - 23/03/19
[e]: [email protected]
[pe]: [email protected]
[g]: github.com/shahsurajk
[twtr]: @shahsurajk
______ ________ __ __
/ \| \ | \| \
| $$$$$$\\$$$$$$$$______ | $$| $$ __
| $$ | $$ | $$ | \ | $$| $$ / \
| $$ | $$ | $$ \$$$$$$\| $$| $$_/ $$
| $$ _| $$ | $$ / $$| $$| $$ $$
| $$/ \ $$ | $$ | $$$$$$$| $$| $$$$$$\
\$$ $$ $$ | $$ \$$ $$| $$| $$ \$$\
\$$$$$$\ \$$ \$$$$$$$ \$$ \$$ \$$
\$$$
- A better dailer.
[g]: github.com/quiph
[p]: https://play.google.com/store/apps/details?id=com.qtalk.app
[j]: https://angel.co/quiph/jobs
___ __ ___ ___ ________ _________ ________
|\ \ |\ \|\ \|\ \|\ __ \|\___ ___\\_____ \
\ \ \ \ \ \ \ \\\ \ \ \|\ \|___ \ \_\|____|\ \
\ \ \ __\ \ \ \ __ \ \ __ \ \ \ \ \ \__\
\ \ \|\__\_\ \ \ \ \ \ \ \ \ \ \ \ \ \|__|
\ \____________\ \__\ \__\ \__\ \__\ \ \__\ ___
\|____________|\|__|\|__|\|__|\|__| \|__| |\__\
\|__|
Inline functions in Kotlin stitch pieces of code together when used as a lambda.
- Also called as an higher-order function.
- Introduced in Java 8.
- Use functions as Objects.
- Evaluated at runtime.
- Increase runtime memory usage
- Increase in object creation
- Not backwards compatible
Example 1:
fun testLambdas(index: Int, myLambda: (index: Int) -> Unit){
myLambda.invoke(index+1)
}
fun myBigLoop(){
(0 .. 50).forEach {
testLambdas(it) { lambdaValue->
println(lambdaValue)
}
}
}
Decompile example 1:
public static final void myBigLoop() {
byte var0 = 0;
Iterable $receiver$iv = (Iterable)(new IntRange(var0, 50));
Iterator var1 = $receiver$iv.iterator();
while(var1.hasNext()) {
int element$iv = ((IntIterator)var1).nextInt();
int var4 = false;
testLambdas(element$iv, (Function1)PresentationKt$myBigLoop$1$1.INSTANCE);
}
}
// Kotlin complier generates a singleton for lambdas without closure.
// but for lambdas with closure, a new instance will be created everytime.
final class PresentationKt$myBigLoop$1$1 extends Lambda implements Function1 {
public static final PresentationKt$myBigLoop$1$1 INSTANCE = new PresentationKt$myBigLoop$1$1();
// Note boxing and unboxing of the int variable, this is painful too!
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object var1) {
this.invoke(((Number)var1).intValue()+1);
return Unit.INSTANCE;
}
public final void invoke(int lambdaValue) {
System.out.println(lambdaValue);
}
PresentationKt$myBigLoop$1$1() {
super(1);
}
}
In worst cases it can even create a new instance of the class Function1
for every iteration!
██╗ ██╗ ██████╗ ██╗ ██╗██████╗
██║ ██║██╔═══██╗██║ ██║╚════██╗
███████║██║ ██║██║ █╗ ██║ ▄███╔╝
██╔══██║██║ ██║██║███╗██║ ▀▀══╝
██║ ██║╚██████╔╝╚███╔███╔╝ ██╗
╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚═╝
When you use the inline
keyword with a function, the compiler takes in extra effort and places the codeblock inside the parent function scope instead of using objects.
TLDR; It pastes the code inside the lambda block to the parent function.
Reiterating example 1:
What we really wanted with example 1,
fun myBigLoop(){
(0..50).forEach{
val finalVal = it+1
println(finalVal)
}
}
This would be the best case scenario right?
Example 2:
inline fun testLambdas(index: Int, myLambda: (index: Int) -> Unit){
myLambda.invoke(index+1)
}
__ __ _ _ _
\ \ / / ___ (_) | | __ _ | |
\ V / / _ \ | | | | / _` | |_|
_\_/_ \___/ _|_|_ _|_|_ \__,_| _(_)_
_| """"|_|"""""|_|"""""|_|"""""|_|"""""|_| """ |
"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'
public final class PresentationKt {
// the compiler generated a pure lambda function as well, just for compatibility sake.
public static final void testLambdas(int index, @NotNull Function1 myLambda) {
int $i$f$testLambdas = 0;
Intrinsics.checkParameterIsNotNull(myLambda, "myLambda");
myLambda.invoke(index + 1);
}
public static final void myBigLoop() {
byte var0 = 0;
Iterable $receiver$iv = (Iterable)(new IntRange(var0, 50));
Iterator var1 = $receiver$iv.iterator();
while(var1.hasNext()) {
int element$iv = ((IntIterator)var1).nextInt();
int var4 = false;
int $i$f$testLambdas = false;
// the logic inside the lambda, performed here locally! Magical isn't it?
int lambdaValue = element$iv + 1;
int var7 = false;
System.out.println(lambdaValue);
}
}
The only difference between example 1 and example 2 is the inline keyword in front of the function!
+-+-+-+-+-+-+-+
|i|n|l|i|n|e|,|
+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+
|c|r|o|s|s|i|n|l|i|n|e|,|
+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+
|n|o|i|n|l|i|n|e|
+-+-+-+-+-+-+-+-+
inline
takes the block inside the lambda and stitches it into the parent function.
If a function doesn't actually need inlining, the compiler throws a warning saying "Performance impact" cause there's nothing to be inlined, yet the lambda is marked as inline
which forces the compiler to perform more effort!
Consider this extention to the original example 2,
Example 3:
inline fun wastedInline(index: Int){
testLambda(index)
}
Ths inline
modifier here is of no use cause there's nothing to be inlined!
This is an argument specifier, if an argument in an inlined function is marked as crossinline
it will not allow the function to have a non-local return.
Simple, anything which is not local!
Example 4:
fun myEmptyFunction(){
return crossInlineTry {
// this will throw an error saying return not allowed here
return
// this wont, see how we're just returning from the current scope. The parent will still perform operations
// after this line
return@crossInlineTry
}
}
inline fun crossInlineTry(crossinline csi: ()->Unit){
csi.invoke()
}
- Perform operations after the lambda
- Restrict non-local returns.
Best example, forEach
! Kotlin doesn't have break
, break can be implemented by making the value capture inside forEach
as crossinline
(note the _Collections.kt class doesn't have this, this is just a thought.) thus instead of break one can simply do return@forEach
which currently does work of a continue
!
A no brainer, but as the doc says:
In case you want only some of the lambdas passed to an inline function to be inlined
Example 5:
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { ... }
- For reusability, if you're have an existing java based lambda, to use it in compatiblity with kotlin.
- There could also be a scenario where
inline
-ing something can cause compilation errors etc.
_____ _ ___ _
|_ _| |_ ___ / __|___ ___ __| |
| | | ' \/ -_) | (_ / _ \/ _ \/ _` |_
|_| |_||_\___| \___\___/\___/\__,_( )
_ _ _ _ |/ _
| |_| |_ ___ | |__ __ _ __| | __ _ _ _ __| |
| _| ' \/ -_) | '_ \/ _` / _` | / _` | ' \/ _` |
\__|_||_\___| |_.__/\__,_\__,_| \__,_|_||_\__,_|
_ _ _ _
| |_| |_ ___ _ _ __ _| |_ _| |
| _| ' \/ -_) | || / _` | | || |_|
\__|_||_\___| \_,_\__, |_|\_, (_)
|___/ |__/
- Saves memory
- Reduces runtime overload
- Helps making code modular, while still making use of the underlying best practices
- Many, many components in Kotlin as based on
inline
functions,- Coroutines
reified
functions- Standards.kt helper functions (
forEach
,also
etc)
inline
functions are evaluated at compile-time, thus increasing overall compile time taken- Value captured inside a closure can be misleading sometimes.
- "Developer error" of forgetting the
inline
keyword! (there are lint errors for usinginline
improperly suggesting performance impact, but not the other way around!)
- Sometimes it becomes difficult to keep track and to remember proper usages of
inline
,crossinline
andnoinline
'########:'##::::'##:'########:'##::::'##:'########::'########:
##.....:: ##:::: ##:... ##..:: ##:::: ##: ##.... ##: ##.....::
##::::::: ##:::: ##:::: ##:::: ##:::: ##: ##:::: ##: ##:::::::
######::: ##:::: ##:::: ##:::: ##:::: ##: ########:: ######:::
##...:::: ##:::: ##:::: ##:::: ##:::: ##: ##.. ##::: ##...::::
##::::::: ##:::: ##:::: ##:::: ##:::: ##: ##::. ##:: ##:::::::
##:::::::. #######::::: ##::::. #######:: ##:::. ##: ########:
..:::::::::.......::::::..::::::.......:::..:::::..::........::
-
inline
classes. Experimental as of 1.3.21 but gets all the advantages of an inline function to the class level!- Inline classes are not present during compile time, thus saving a lot of memory!
- Plus they make good database IDs - Jake Wharton (inline classes refactored themselves after he said this :P)
- For now inline classes support only one variable, but who knows!
-
A very active community.
-
KEEP: Kotlin Evolution and Enhancement Process, JetBrain's way of asking the community for enhancements and showcasing to the world as well what it can do! Some notable things implemented due to KEEP
- Coroutines, well, let's just not talk about this.
- Inline classes, still a WIP but I use it in production!
- Unsigned int, long. The minute you realize that this is just a smarter way, a textbook implementation of inline classes, you'll just be mesmerizied by the boundaries kotlin has set for devs!
_____ _ _
|_ _| |__ __ _ _ __ | | __ _ _ ___ _ _
| | | '_ \ / _` | '_ \| |/ / | | | |/ _ \| | | |
| | | | | | (_| | | | | < | |_| | (_) | |_| |
|_| |_| |_|\__,_|_| |_|_|\_\ \__, |\___/ \__,_|
|___/
Heartly thanks to: ASCII Art generator link