SlideShare a Scribd company logo
© Instil Software 2020
Lies Told By The Kotlin
Compiler
Looking under the hood of Kotlin JVM
@GarthGilmour @ryangadams
https://instil.co
Lies Told By The Kotlin Compiler
– Kotlin is an awesome language!
– It provides many wonderful features
– These features don’t exist on the supported
platforms
– We need the compiler to emulate them
– Initially we don’t care how this is done
introducing this talk
why do we need lies?
the lies are a good thing
they create a more productive world
"Being abstract is something profoundly different from
being vague … The purpose of abstraction is not to be
vague, but to create a new semantic level in which one can
be absolutely precise.”
Edsger W. Dijkstra
– Nothing is ever hidden in software
– We can decompile JVM bytecode produced
via the Kotlin compiler
– In the future we could use IR
how do we find the truth?
by using a decompiler
Lies Told By The Kotlin Compiler
introducing javap
the java bytecode decompiler
% javap
Usage: javap <options> <classes>
where possible options include:
...
-p -private Show all classes and members
-c Disassemble the code
-s Print internal type signatures
...
--module-path <path> Specify where to find application modules
--system <jdk> Specify where to find system modules
...
-cp <path> Specify where to find user class files
...
– The Kotlin Language
– Suspending Functions & Coroutines
– Jetpack Compose (Desktop and Web)
Three different levels of deception
lies, damned lies and jetpack compose 
1
Lies from the
core language
Free Functions
//Program.kt
fun printMsg(text: String) = println(text)
fun main() = printMsg("Bonjour Kotlin Koders!")
free functions
Bonjour Kotlin Koders!
public final class ProgramKt {
public static final void printMsg(String);
Code:
15: return
public static final void main();
Code:
5: return
public static void main(String[]);
Code:
3: return
}
free functions
Nested Functions
fun main() {
fun printMsg(text: String) = println(text)
printMsg("Bonjour Kotlin Koders!")
}
nested functions
Bonjour Kotlin Koders!
public final class ProgramKt {
public static final void main();
Code:
0: ldc #8 // String Bonjour Kotlin Koders!
2: invokestatic #12 // Method main$printMsg:(String;)V
5: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #15 // Method main:()V
3: return
nested functions
private static final void main$printMsg(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: getstatic #23 // Field System.out
5: aload_0
6: invokevirtual #29 // Method PrintStream.println:(Object)V
9: return
}
nested functions
fun main() {
demo(123)
demo(45.6)
}
fun demo(input: Int) {
fun printMsg(text: String) = println(text)
printMsg("Hello Kotlin Koders!")
}
fun demo(input: Double) {
fun printMsg(text: String) = println(text)
printMsg("Bonjour Kotlin Koders!")
}
nested functions - extended
Hello Kotlin Koders!
Bonjour Kotlin Koders!
public static final void demo(int);
Code:
0: ldc #17 // String Hello Kotlin Koders!
2: invokestatic #21 // Method demo$printMsg:(String;)V
5: return
public static final void demo(double);
Code:
0: ldc #25 // String Bonjour Kotlin Koders!
2: invokestatic #28 // Method "demo$printMsg-0":(String;)V
5: return
nested functions - extended
private static final void demo$printMsg(String);
Code:
0: iconst_0
1: istore_1
2: getstatic #40 // Field System.out
5: aload_0
6: invokevirtual #46 // Method PrintStream.println:(Object;)V
9: return
private static final void demo$printMsg-0(String);
Code:
0: iconst_0
1: istore_1
2: getstatic #40 // Field System.out
5: aload_0
6: invokevirtual #46 // Method PrintStream.println:(Object;)V
9: return
}
nested functions - extended
Primary Constructors
class Person(val name: String, var age: Int) {
private val fullName: String
init {
fullName = "$name Jones"
}
override fun toString() = "$fullName aged $age"
}
fun main() {
val person = Person("Bridget", 30)
println(person)
}
constructors
Bridget Jones aged 30
public final class Person {
private final String name;
private int age;
private final String fullName;
public Person(String, int);
Code:
26: ldc #27 // String Jones
28: invokestatic #31 // Intrinsics.stringPlus:(String; Object;)String;
31: putfield #34 // Field fullName:String;
34: nop
35: return
public final String getName();
public final int getAge();
public final void setAge(int);
public String toString();
}
constructors
Extension Methods
class Person(val name: String)
fun Person.sayHello() = println("Hello from $name")
fun String.times(num: Int) = (1..num).joinToString { "$this" }
fun main() {
val person = Person("Jane")
person.sayHello()
println("Dave".times(3))
}
extension methods
Hello from Jane
Dave, Dave, Dave
public static final void sayHello(Person);
Code:
...
25: return
public static final String times(String, int);
Code:
...
40: return
extension methods
Destructuring
destructuring
data class Person(val name: String, val age: Int)
fun main() {
val person = Person("Lucy", 36)
val (x, y) = person
println(x)
println(y)
}
Lucy
36
destructuring
public final Person {
private final String name;
private final int age;
public Person(String, int);
public final String getName();
public final int getAge();
public final String component1();
public final int component2();
public final Person copy(String, int);
public static Person copy$default(Person, String, int, int, Object);
public java.lang.String toString();
public int hashCode();
public boolean equals(java.lang.Object);
}
destructuring
public final class ProgramKt {
public static final void main();
Code:
...
15: invokevirtual #18 // Person.component1:()String;
18: astore_2
19: aload_1
20: invokevirtual #22 // Person.component2:()I
23: istore_3
...
44: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #46 // Method main:()V
3: return
}
Object Declarations
object declarations
object Math {
fun add(no1: Int, no2: Int) = no1 + no2
}
fun main() {
println(Math.add(12,34))
}
46
object declarations
public final class Math {
public static final Math INSTANCE;
private Math();
public final int add(int, int);
static {};
Code:
0: new #2 // class Math
3: dup
4: invokespecial #17 // Method "<init>":()V
7: putstatic #20 // Field INSTANCE:Math;
10: return
}
object declarations
public final class ProgramKt {
public static final void main();
Code:
0: getstatic #12 // Field Math.INSTANCE:Math;
3: bipush 12
5: bipush 34
7: invokevirtual #16 // Method Math.add:(II)I
10: istore_0
11: iconst_0
12: istore_1
13: getstatic #22 // Field System.out;
16: iload_0
17: invokevirtual #28 // Method PrintStream.println:(I)V
20: return
public static void main(String[]);
}
Companion Objects
class Employee(val name: String, val dept: String) {
companion object {
fun buildForHR(name: String) = Employee(name, "HR")
fun buildForIT(name: String) = Employee(name, "IT")
}
override fun toString() = "$name working in $dept"
}
fun main() {
val emp1 = Employee.buildForHR("Dave")
val emp2 = Employee.buildForIT("Jane")
println(emp1)
println(emp2)
}
companion objects
Dave working in HR
Jane working in IT
public final class lang.eg8.Employee {
public static final lang.eg8.Employee$Companion Companion;
private final String name;
private final String dept;
public Employee(String, String);
public final String getName();
public final String getDept();
public String toString();
static {};
Code:
0: new #45 // class Employee$Companion
3: dup
4: aconst_null
5: invokespecial #48 // Employee$Companion."<init>"
8: putstatic #52 // Field Companion:Employee$Companion;
11: return
}
companion objects
Enumerations
enum class Colour {
Red,
Green,
Blue
}
fun main() {
Colour.values().forEach(::println)
}
Enumerations
Red
Green
Blue
public final class Colour extends java.lang.Enum<Colour> {
public static final Colour Red;
public static final Colour Green;
public static final Colour Blue;
private static final Colour[] $VALUES;
private Colour();
public static Colour[] values();
public static Colour valueOf(String);
private static final Colour[] $values();
Enumerations
static {};
Code:
0: new #2 // class Colour
3: dup
4: ldc #47 // String Red
6: iconst_0
7: invokespecial #48 // Method "<init>":(String;I)V
10: putstatic #39 // Field Red:Colour;
13: new #2 // class Colour
16: dup
17: ldc #49 // String Green
19: iconst_1
20: invokespecial #48 // Method "<init>":(String;I)V
23: putstatic #42 // Field Green:Colour;
Enumerations
26: new #2 // class Colour
30: ldc #50 // String Blue
32: iconst_2
33: invokespecial #48 // Method "<init>":(String;I)V
36: putstatic #45 // Field Blue:Colour;
39: invokestatic #52 // Method $values:()[Colour;
42: putstatic #22 // Field $VALUES:[Colour;
45: return
}
Enumerations
Lambdas With Receivers
data class Person(val name: String, var age: Int)
fun demo(person: Person, action: Person.() -> Unit) = person.apply(action)
fun main() {
val person = Person("Jane", 25)
demo(person) {
age += 10
println(this)
}
}
lambdas with receivers
Person(name=Jane, age=35)
public final class ProgramKt {
public static final Person demo(
Person,
kotlin.jvm.functions.Function1<? super Person, kotlin.Unit>
);
Code:
...
21: invokeinterface #24,2 //Function1.invoke:(Object;)Object;
...
public static final void main();
Code:
...
13: getstatic #42 // Field ProgramKt$main$1.INSTANCE:ProgramKt$main$1;
16: checkcast #20 // class kotlin/jvm/functions/Function1
19: invokestatic #44 // Method demo:(Person;Function1;)Person;
...
lambdas with receivers
public interface Function1<P1, R> extends Function<R> {
public abstract R invoke(P1);
}
lambdas with receivers
javap -cp kotlin-stdlib-1.5.10.jar -c -p kotlin.jvm.functions.Function1
public interface kotlin.Function<R> {
}
javap -cp kotlin-stdlib-1.5.10.jar -c -p kotlin.jvm.functions.Function
public interface Function2<P1, P2, R> extends Function<R> {
public abstract R invoke(P1, P2);
}
lambdas with receivers
javap -cp kotlin-stdlib-1.5.10.jar -c -p kotlin.jvm.functions.Function2
public interface Function3<P1, P2, P3, R> extends Function<R> {
public abstract R invoke(P1, P2, P3);
}
javap -cp kotlin-stdlib-1.5.10.jar -c -p kotlin.jvm.functions.Function3
2
Lies told when
suspending
– Do suspending functions actually suspend?
– Are they really paused and then resumed?
– Let’s use Ktor & Coroutines to investigate
– Because that’s the main use case
– Note other examples exist (e.g. Arrow)
consider suspending functions
is it all a lie?
– First, we write some entity classes
– To represent food and beverages
– Second, we write a server
– Which provides options for breakfast
– Finally, we write a client that suspends
– This is the code we will dissasemble
let’s order breakfast
via a REST endpoint
Data Model
enum class BeverageSize {
Small,
Medium,
Large
}
enum class BeverageType {
Expresso,
Americano,
CafeAuLait
}
@Serializable
class Beverage(val type: BeverageType, val size: BeverageSize) {
fun drink() = println("Drinking a $size $type")
}
our data model
@Serializable
class Food(
private val name: String,
private val servingSize: Int,
private val withChocolate: Boolean
) {
fun eat() {
val type = if(withChocolate) "chocolate" else "plain"
println("Eating $servingSize $type $name")
}
}
class Breakfast(private val beverage: Beverage, private val food: Food) {
fun consume() {
beverage.drink()
food.eat()
}
}
our data model
Server-Side
fun Application.configureBreakfast() {
routing {
get("/breakfast/beverage") {
call.respond(selectBeverage())
}
post("/breakfast/food") {
val beverage = call.receive<Beverage>()
call.respond(selectFood(beverage))
}
}
}
our server-side
fun selectBeverage(): Beverage {
fun inFrance() = Locale.getDefault() == FRANCE
fun beforeNoon() = LocalTime.now().isBefore(LocalTime.NOON)
val type = if (inFrance()) CafeAuLait else Americano
val size = if (beforeNoon()) Large else Medium
return Beverage(type, size)
}
fun selectFood(beverage: Beverage): Food {
val serving = if (beverage.size == Large) 3 else 2
return if (beverage.type == CafeAuLait) {
Food("Croissants", serving, true)
} else {
Food("Pancakes", serving, false)
}
}
our server-side
Client-Side
fun main() = runBlocking {
printInDetail("Program starts")
val client = buildHttpClient()
client.use {
val breakfast = orderBreakfast(client)
printInDetail("Breakfast ordered")
breakfast.consume()
}
printInDetail("Program ends")
}
our client
[Program starts at 12:21:16 on 1]
[Ordering breakfast at 12:21:16 on 24]
[Breakfast ordered at 12:21:17 on 1]
Drinking a Medium Americano
Eating 2 plain Pancakes
[Program ends at 12:21:17 on 1]
fun printInDetail(item: String) {
fun timeNow(): String {
val formatter = DateTimeFormatter.ofPattern("HH:mm:ss")
return formatter.format(LocalTime.now())
}
fun timeAndThread(item: String) =
"[$item at ${timeNow()} on ${Thread.currentThread().id}]"
println(timeAndThread(item))
}
our client
private fun buildHttpClient() = HttpClient(CIO) {
install(JsonFeature)
defaultRequest {
host = "0.0.0.0"
port = 8080
url {
protocol = URLProtocol.HTTP
}
}
}
our client
suspend fun orderBreakfast(
client: HttpClient
): Breakfast = withContext(Dispatchers.IO) {
printInDetail("Ordering breakfast")
val beverage: Beverage = orderBeverage(client)
val food: Food = orderFood(client, beverage)
Breakfast(beverage, food)
}
our client
private suspend fun orderFood(it: HttpClient, beverage: Beverage): Food =
it.post("/breakfast/food") {
body = beverage
contentType(ContentType.Application.Json)
}
private suspend fun orderBeverage(it: HttpClient): Beverage =
it.get("/breakfast/beverage") {
accept(ContentType.Application.Json)
}
our client
– Note this is a suspending function
– Which calls two other suspending functions
let’s disassemble ‘orderBreakfast’
to see what lies are found within...
public static final Object orderBreakfast(...) {
return BuildersKt.withContext(... , ... {
...
public final Object invokeSuspend(...) {
...
label17: {
...
switch(this.label) {
case 0:
...
case 1:
...
case 2:
...
default:
...
}
...
}
...
}
...
}), ...);
}
let’s disassemble ‘orderBreakfast’
why it’s just a big switch statement!
...nested inside a labelled block
understanding suspending functions
label17: {
Object var4 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
HttpClient var5;
switch(this.label) {
case 0:
ResultKt.throwOnFailure($result);
UtilsKt.printInDetail("Ordering breakfast");
var5 = client;
this.label = 1;
var10000 = ProgramKt.orderBeverage(var5, this);
if (var10000 == var4) {
return var4;
}
break;
var4 will hold the
constant value for
signaling suspension
we suspend by returning if that’s what
the orderBeverage function wants
how do suspending functions work?
via continuations...
Lies Told By The Kotlin Compiler
understanding suspending functions
beverage = (Beverage)var10000;
var5 = client;
this.L$0 = beverage;
this.label = 2;
var10000 = ProgramKt.orderFood(var5, beverage, this);
if (var10000 == var4) {
return var4;
}
when we have the return value
from orderBeverage we store it
and set the label to 2
we suspend by returning if that’s
what the orderFood function wants
understanding suspending functions
case 2:
beverage = (Beverage)this.L$0;
ResultKt.throwOnFailure($result);
var10000 = $result;
break label17;
when we have the return value from
orderFood we retrieve the beverage from
storage, put the food in var10000 and use a
labelled block to exit the switch statement
understanding suspending functions
public final Object invokeSuspend(@NotNull Object $result) {
Object var10000;
Beverage beverage;
label17: {
//switch statement lives here
}
Food food = (Food)var10000;
return new Breakfast(beverage, food);
}
Once the mechanics of calling the
other suspending functions are
complete, we can build the final return
value from the incremental results
– Continuation objects hold labels and
intermediate results
– A switch statement resumes
processing at the correct point
– A labelled block short-circuits the
switch when we are done
suspending functions do not suspend!!!
they return and are re-invoked
3
Lies told by
compose
Lies Told By The Kotlin Compiler
Lies Told By The Kotlin Compiler
working with desktop compose
creating a simple calculator
– Compose is implemented as a DSL
– But goes beyond a purely Internal DSL
– A compiler plugin is required
– To generate supporting infrastructure
– This implies we are being deceived
– Let’s look at a sample application...
fun main() = application {
Window(...) {
val savedTotal = remember { mutableStateOf(0) }
val displayedTotal = remember { mutableStateOf(0) }
val operationOngoing = remember { mutableStateOf(Operation.None) }
val operationJustChanged = remember { mutableStateOf(false) }
//Event Handlers Omitted
InstilTheme {
Column {
Row {
DisplayText(text = "${displayedTotal.value}")
}
Row {
NumberButtonColumn(numberSelected)
OperationButtonColumn(operationSelected, clearSelected, equalsSelected)
}
}
}
}
}
building a calculator via compose
@Composable
fun InstilTheme(content: @Composable () -> Unit) {
val colors = MaterialTheme.colors.copy(primary = Color.LightGray)
MaterialTheme(content = content, colors = colors)
}
@Composable
fun DisplayText(text: String) =
Text(
text = text,
style = TextStyle(color = Color.Black, fontSize = 28.sp),
modifier = Modifier.padding(all = 10.dp)
)
building a calculator via compose
@Composable
fun NumberButton(onClick: () -> Unit, number: Int) =
Button(
onClick = onClick,
modifier = Modifier.padding(all = 5.dp)
) {
Text(
number.toString(),
style = TextStyle(color = Color.Black, fontSize = 18.sp)
)
}
@Composable
fun NumberButtonRow(range: IntRange, onClick: (Int) -> Unit) = Row {
range.forEach { num ->
NumberButton(onClick = { onClick(num) }, number = num)
}
}
building a calculator via compose
@Composable
fun NumberButtonColumn(onClick: (Int) -> Unit) = Column {
NumberButtonRow(1..3, onClick)
NumberButtonRow(4..6, onClick)
NumberButtonRow(7..9, onClick)
NumberButtonRow(0..0, onClick)
}
building a calculator via compose
@Composable
fun OperationButton(onClick: () -> Unit, label: String) =
Button(
onClick = onClick,
modifier = Modifier.padding(all = 2.dp)
) {
Text(
label,
style = TextStyle(color = Color.Black, fontSize = 14.sp)
)
}
building a calculator via compose
@Composable
fun OperationButtonColumn(
onSelect: (Operation) -> Unit,
onClear: () -> Unit,
onEquals: () -> Unit
) = Column {
listOf(
{ onSelect(Add) } to "+",
{ onSelect(Subtract) } to "-",
{ onSelect(Multiply) } to "*",
{ onSelect(Divide) } to "/",
onClear to "Clear",
onEquals to "="
).forEach {
OperationButton(onClick = it.first, label = it.second)
}
}
building a calculator via compose
@Composable
fun DisplayText(text: String) =
Text(
text = text,
style = TextStyle(color = Color.Black, fontSize = 28.sp),
modifier = Modifier.padding(all = 10.dp)
)
public static final void DisplayText(String, Composer, int);
Code:
0: aload_0
// Lots and lots of bytecode...
791: return
decompiling the calculator
– Every compose functions takes:
– An object of type composer
– A unique integer value
– The composer builds the logical tree of widgets
– The integer uniquely identifies an instance of a widget
decompiling the calculator
the additional parameters
public final class CalculatorKt {
public static final void InstilTheme(
Function2<? super Composer, ? super Integer, Unit>,
Composer,
int
);
public static final void DisplayText(
String,
Composer,
int
);
public static final void NumberButton(
Function0<Unit>,
int,
Composer,
int
);
decompiling the calculator
public static final void OperationButton(
Function0<Unit>,
String,
Composer,
int
);
public static final void OperationButtonColumn(
Function1<? super Operation, Unit>,
Function0<Unit>, Function0<Unit>,
Composer,
int
);
decompiling the calculator
public static final void NumberButtonRow(
IntRange,
Function1<? super Integer, Unit>,
Composer,
int
);
public static final void NumberButtonColumn(
Function1<? super Integer, Unit>,
Composer,
int
);
public static final void main();
public static void main(String[]);
}
decompiling the calculator
– Composable functions support Positional Memoization
– Memory of how they were called at each point on the graph
– They can also be re-invoked at any time (Recomposition)
– This is accomplished via a Gap Buffer / Slot Table
decompiling the calculator
groups and the slot table
– On every call we insert a new group into the table
– The group is identified by the integer parameter
– Nested components add groups for child components
– We walk the graph depth first to build a linear structure
decompiling the calculator
groups and the slot table
Group
(123)
Group
(456)
Group
(789)
public static final void DisplayText(String, Composer, int);
Code:
7: ldc #110 // int 1244737340
9: invokeinterface #25, 2 // Composer.startRestartGroup:(I)
...
33: invokeinterface #37, 2 // Composer.changed:(Object)
...
58: invokeinterface #41, 1 // Composer.getSkipping:()
...
167: invokeinterface #79, 1 // Composer.skipToGroupEnd:()V
...
173: invokeinterface #83, 1 // Composer.endRestartGroup:()
...
202: invokeinterface #97, 2 // ScopeUpdateScope.updateScope:(Function2)
207: return
decompiling the calculator
Lies Told By The Kotlin Compiler
4
Conclusions
– They provide advanced features
– They provide consistency across all the
platforms the language supports
– They let us work at higher levels of abstraction
(with certainty)
– They get us home by 5pm 
the lies are everywhere!
...and that’s a good thing
Questions?

More Related Content

Similar to Lies Told By The Kotlin Compiler (20)

PDF
Kotlin for Android Developers - 3
Mohamed Nabil, MSc.
 
PDF
Kotlin/Everywhere GDG Bhubaneswar 2019
Sriyank Siddhartha
 
PPTX
Benefits of Kotlin
Benjamin Waye
 
PDF
ADG Poznań - Kotlin for Android developers
Bartosz Kosarzycki
 
PDF
Kotlin cheat sheet by ekito
Arnaud Giuliani
 
PDF
2 kotlin vs. java: what java has that kotlin does not
Sergey Bandysik
 
PPT
The Kotlin Programming Language
intelliyole
 
PPTX
Introduction to kotlin + spring boot demo
Muhammad Abdullah
 
PPTX
Kotlin Basic & Android Programming
Kongu Engineering College, Perundurai, Erode
 
PDF
Privet Kotlin (Windy City DevFest)
Cody Engel
 
PDF
Kotlin @ Devoxx 2011
Andrey Breslav
 
PDF
Kotlin Slides from Devoxx 2011
Andrey Breslav
 
PDF
Kotlin: A pragmatic language by JetBrains
Jigar Gosar
 
PDF
Kotlin - The Swiss army knife of programming languages - Visma Mobile Meet-up...
Tudor Dragan
 
PDF
Bologna Developer Zone - About Kotlin
Marco Vasapollo
 
PDF
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Codemotion
 
PPTX
Kotlin Language Features - A Java comparison
Ed Austin
 
PPTX
Building Mobile Apps with Android
Kurt Renzo Acosta
 
PDF
Kotlin intro
Elifarley Cruz
 
Kotlin for Android Developers - 3
Mohamed Nabil, MSc.
 
Kotlin/Everywhere GDG Bhubaneswar 2019
Sriyank Siddhartha
 
Benefits of Kotlin
Benjamin Waye
 
ADG Poznań - Kotlin for Android developers
Bartosz Kosarzycki
 
Kotlin cheat sheet by ekito
Arnaud Giuliani
 
2 kotlin vs. java: what java has that kotlin does not
Sergey Bandysik
 
The Kotlin Programming Language
intelliyole
 
Introduction to kotlin + spring boot demo
Muhammad Abdullah
 
Kotlin Basic & Android Programming
Kongu Engineering College, Perundurai, Erode
 
Privet Kotlin (Windy City DevFest)
Cody Engel
 
Kotlin @ Devoxx 2011
Andrey Breslav
 
Kotlin Slides from Devoxx 2011
Andrey Breslav
 
Kotlin: A pragmatic language by JetBrains
Jigar Gosar
 
Kotlin - The Swiss army knife of programming languages - Visma Mobile Meet-up...
Tudor Dragan
 
Bologna Developer Zone - About Kotlin
Marco Vasapollo
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Codemotion
 
Kotlin Language Features - A Java comparison
Ed Austin
 
Building Mobile Apps with Android
Kurt Renzo Acosta
 
Kotlin intro
Elifarley Cruz
 

More from Garth Gilmour (20)

PPTX
Compose in Theory
Garth Gilmour
 
PPTX
TypeScript Vs. KotlinJS
Garth Gilmour
 
PPTX
Shut Up And Eat Your Veg
Garth Gilmour
 
PPTX
A TypeScript Fans KotlinJS Adventures
Garth Gilmour
 
PPTX
The Heat Death Of Enterprise IT
Garth Gilmour
 
PPTX
Type Driven Development with TypeScript
Garth Gilmour
 
PPTX
Generics On The JVM (What you don't know will hurt you)
Garth Gilmour
 
PPTX
Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space
Garth Gilmour
 
PPTX
Is Software Engineering A Profession?
Garth Gilmour
 
PPTX
Social Distancing is not Behaving Distantly
Garth Gilmour
 
PDF
The Great Scala Makeover
Garth Gilmour
 
PDF
Transitioning Android Teams Into Kotlin
Garth Gilmour
 
PDF
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Garth Gilmour
 
PDF
The Three Horse Race
Garth Gilmour
 
PDF
The Bestiary of Pure Functional Programming
Garth Gilmour
 
PDF
BelTech 2019 Presenters Workshop
Garth Gilmour
 
PDF
Kotlin The Whole Damn Family
Garth Gilmour
 
PDF
The Philosophy of DDD
Garth Gilmour
 
PDF
10 Big Ideas from Industry
Garth Gilmour
 
PDF
'Full Stack Kotlin' Workshop at KotlinConf
Garth Gilmour
 
Compose in Theory
Garth Gilmour
 
TypeScript Vs. KotlinJS
Garth Gilmour
 
Shut Up And Eat Your Veg
Garth Gilmour
 
A TypeScript Fans KotlinJS Adventures
Garth Gilmour
 
The Heat Death Of Enterprise IT
Garth Gilmour
 
Type Driven Development with TypeScript
Garth Gilmour
 
Generics On The JVM (What you don't know will hurt you)
Garth Gilmour
 
Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space
Garth Gilmour
 
Is Software Engineering A Profession?
Garth Gilmour
 
Social Distancing is not Behaving Distantly
Garth Gilmour
 
The Great Scala Makeover
Garth Gilmour
 
Transitioning Android Teams Into Kotlin
Garth Gilmour
 
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Garth Gilmour
 
The Three Horse Race
Garth Gilmour
 
The Bestiary of Pure Functional Programming
Garth Gilmour
 
BelTech 2019 Presenters Workshop
Garth Gilmour
 
Kotlin The Whole Damn Family
Garth Gilmour
 
The Philosophy of DDD
Garth Gilmour
 
10 Big Ideas from Industry
Garth Gilmour
 
'Full Stack Kotlin' Workshop at KotlinConf
Garth Gilmour
 

Recently uploaded (20)

PPTX
BB FlashBack Pro 5.61.0.4843 With Crack Free Download
cracked shares
 
PPT
24-BuildingGUIs Complete Materials in Java.ppt
javidmiakhil63
 
PPTX
How Can Reporting Tools Improve Marketing Performance.pptx
Varsha Nayak
 
PDF
Introduction to Apache Iceberg™ & Tableflow
Alluxio, Inc.
 
PPTX
Build a Custom Agent for Agentic Testing.pptx
klpathrudu
 
PDF
Windows 10 Professional Preactivated.pdf
asghxhsagxjah
 
PDF
Softaken CSV to vCard Converter accurately converts CSV files to vCard
markwillsonmw004
 
PDF
Show Which Projects Support Your Strategy and Deliver Results with OnePlan df
OnePlan Solutions
 
PDF
Notification System for Construction Logistics Application
Safe Software
 
PDF
How to get the licensing right for Microsoft Core Infrastructure Server Suite...
Q-Advise
 
PDF
How Attendance Management Software is Revolutionizing Education.pdf
Pikmykid
 
PDF
custom development enhancement | Togglenow.pdf
aswinisuhu
 
PPTX
Lec 2 Compiler, Interpreter, linker, loader.pptx
javidmiakhil63
 
PDF
ERP Consulting Services and Solutions by Contetra Pvt Ltd
jayjani123
 
PDF
intro_to_cpp_namespace_robotics_corner.pdf
MohamedSaied877003
 
PPTX
leaf desease detection using machine learning.pptx
kdjeevan35
 
PDF
Code and No-Code Journeys: The Maintenance Shortcut
Applitools
 
PDF
AI Prompts Cheat Code prompt engineering
Avijit Kumar Roy
 
PDF
Australian Enterprises Need Project Service Automation
Navision India
 
PPTX
API DOCUMENTATION | API INTEGRATION PLATFORM
philipnathen82
 
BB FlashBack Pro 5.61.0.4843 With Crack Free Download
cracked shares
 
24-BuildingGUIs Complete Materials in Java.ppt
javidmiakhil63
 
How Can Reporting Tools Improve Marketing Performance.pptx
Varsha Nayak
 
Introduction to Apache Iceberg™ & Tableflow
Alluxio, Inc.
 
Build a Custom Agent for Agentic Testing.pptx
klpathrudu
 
Windows 10 Professional Preactivated.pdf
asghxhsagxjah
 
Softaken CSV to vCard Converter accurately converts CSV files to vCard
markwillsonmw004
 
Show Which Projects Support Your Strategy and Deliver Results with OnePlan df
OnePlan Solutions
 
Notification System for Construction Logistics Application
Safe Software
 
How to get the licensing right for Microsoft Core Infrastructure Server Suite...
Q-Advise
 
How Attendance Management Software is Revolutionizing Education.pdf
Pikmykid
 
custom development enhancement | Togglenow.pdf
aswinisuhu
 
Lec 2 Compiler, Interpreter, linker, loader.pptx
javidmiakhil63
 
ERP Consulting Services and Solutions by Contetra Pvt Ltd
jayjani123
 
intro_to_cpp_namespace_robotics_corner.pdf
MohamedSaied877003
 
leaf desease detection using machine learning.pptx
kdjeevan35
 
Code and No-Code Journeys: The Maintenance Shortcut
Applitools
 
AI Prompts Cheat Code prompt engineering
Avijit Kumar Roy
 
Australian Enterprises Need Project Service Automation
Navision India
 
API DOCUMENTATION | API INTEGRATION PLATFORM
philipnathen82
 

Lies Told By The Kotlin Compiler

  • 1. © Instil Software 2020 Lies Told By The Kotlin Compiler Looking under the hood of Kotlin JVM
  • 4. – Kotlin is an awesome language! – It provides many wonderful features – These features don’t exist on the supported platforms – We need the compiler to emulate them – Initially we don’t care how this is done introducing this talk why do we need lies?
  • 5. the lies are a good thing they create a more productive world "Being abstract is something profoundly different from being vague … The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise.” Edsger W. Dijkstra
  • 6. – Nothing is ever hidden in software – We can decompile JVM bytecode produced via the Kotlin compiler – In the future we could use IR how do we find the truth? by using a decompiler
  • 8. introducing javap the java bytecode decompiler % javap Usage: javap <options> <classes> where possible options include: ... -p -private Show all classes and members -c Disassemble the code -s Print internal type signatures ... --module-path <path> Specify where to find application modules --system <jdk> Specify where to find system modules ... -cp <path> Specify where to find user class files ...
  • 9. – The Kotlin Language – Suspending Functions & Coroutines – Jetpack Compose (Desktop and Web) Three different levels of deception lies, damned lies and jetpack compose 
  • 12. //Program.kt fun printMsg(text: String) = println(text) fun main() = printMsg("Bonjour Kotlin Koders!") free functions Bonjour Kotlin Koders!
  • 13. public final class ProgramKt { public static final void printMsg(String); Code: 15: return public static final void main(); Code: 5: return public static void main(String[]); Code: 3: return } free functions
  • 15. fun main() { fun printMsg(text: String) = println(text) printMsg("Bonjour Kotlin Koders!") } nested functions Bonjour Kotlin Koders!
  • 16. public final class ProgramKt { public static final void main(); Code: 0: ldc #8 // String Bonjour Kotlin Koders! 2: invokestatic #12 // Method main$printMsg:(String;)V 5: return public static void main(java.lang.String[]); Code: 0: invokestatic #15 // Method main:()V 3: return nested functions
  • 17. private static final void main$printMsg(java.lang.String); Code: 0: iconst_0 1: istore_1 2: getstatic #23 // Field System.out 5: aload_0 6: invokevirtual #29 // Method PrintStream.println:(Object)V 9: return } nested functions
  • 18. fun main() { demo(123) demo(45.6) } fun demo(input: Int) { fun printMsg(text: String) = println(text) printMsg("Hello Kotlin Koders!") } fun demo(input: Double) { fun printMsg(text: String) = println(text) printMsg("Bonjour Kotlin Koders!") } nested functions - extended Hello Kotlin Koders! Bonjour Kotlin Koders!
  • 19. public static final void demo(int); Code: 0: ldc #17 // String Hello Kotlin Koders! 2: invokestatic #21 // Method demo$printMsg:(String;)V 5: return public static final void demo(double); Code: 0: ldc #25 // String Bonjour Kotlin Koders! 2: invokestatic #28 // Method "demo$printMsg-0":(String;)V 5: return nested functions - extended
  • 20. private static final void demo$printMsg(String); Code: 0: iconst_0 1: istore_1 2: getstatic #40 // Field System.out 5: aload_0 6: invokevirtual #46 // Method PrintStream.println:(Object;)V 9: return private static final void demo$printMsg-0(String); Code: 0: iconst_0 1: istore_1 2: getstatic #40 // Field System.out 5: aload_0 6: invokevirtual #46 // Method PrintStream.println:(Object;)V 9: return } nested functions - extended
  • 22. class Person(val name: String, var age: Int) { private val fullName: String init { fullName = "$name Jones" } override fun toString() = "$fullName aged $age" } fun main() { val person = Person("Bridget", 30) println(person) } constructors Bridget Jones aged 30
  • 23. public final class Person { private final String name; private int age; private final String fullName; public Person(String, int); Code: 26: ldc #27 // String Jones 28: invokestatic #31 // Intrinsics.stringPlus:(String; Object;)String; 31: putfield #34 // Field fullName:String; 34: nop 35: return public final String getName(); public final int getAge(); public final void setAge(int); public String toString(); } constructors
  • 25. class Person(val name: String) fun Person.sayHello() = println("Hello from $name") fun String.times(num: Int) = (1..num).joinToString { "$this" } fun main() { val person = Person("Jane") person.sayHello() println("Dave".times(3)) } extension methods Hello from Jane Dave, Dave, Dave
  • 26. public static final void sayHello(Person); Code: ... 25: return public static final String times(String, int); Code: ... 40: return extension methods
  • 28. destructuring data class Person(val name: String, val age: Int) fun main() { val person = Person("Lucy", 36) val (x, y) = person println(x) println(y) } Lucy 36
  • 29. destructuring public final Person { private final String name; private final int age; public Person(String, int); public final String getName(); public final int getAge(); public final String component1(); public final int component2(); public final Person copy(String, int); public static Person copy$default(Person, String, int, int, Object); public java.lang.String toString(); public int hashCode(); public boolean equals(java.lang.Object); }
  • 30. destructuring public final class ProgramKt { public static final void main(); Code: ... 15: invokevirtual #18 // Person.component1:()String; 18: astore_2 19: aload_1 20: invokevirtual #22 // Person.component2:()I 23: istore_3 ... 44: return public static void main(java.lang.String[]); Code: 0: invokestatic #46 // Method main:()V 3: return }
  • 32. object declarations object Math { fun add(no1: Int, no2: Int) = no1 + no2 } fun main() { println(Math.add(12,34)) } 46
  • 33. object declarations public final class Math { public static final Math INSTANCE; private Math(); public final int add(int, int); static {}; Code: 0: new #2 // class Math 3: dup 4: invokespecial #17 // Method "<init>":()V 7: putstatic #20 // Field INSTANCE:Math; 10: return }
  • 34. object declarations public final class ProgramKt { public static final void main(); Code: 0: getstatic #12 // Field Math.INSTANCE:Math; 3: bipush 12 5: bipush 34 7: invokevirtual #16 // Method Math.add:(II)I 10: istore_0 11: iconst_0 12: istore_1 13: getstatic #22 // Field System.out; 16: iload_0 17: invokevirtual #28 // Method PrintStream.println:(I)V 20: return public static void main(String[]); }
  • 36. class Employee(val name: String, val dept: String) { companion object { fun buildForHR(name: String) = Employee(name, "HR") fun buildForIT(name: String) = Employee(name, "IT") } override fun toString() = "$name working in $dept" } fun main() { val emp1 = Employee.buildForHR("Dave") val emp2 = Employee.buildForIT("Jane") println(emp1) println(emp2) } companion objects Dave working in HR Jane working in IT
  • 37. public final class lang.eg8.Employee { public static final lang.eg8.Employee$Companion Companion; private final String name; private final String dept; public Employee(String, String); public final String getName(); public final String getDept(); public String toString(); static {}; Code: 0: new #45 // class Employee$Companion 3: dup 4: aconst_null 5: invokespecial #48 // Employee$Companion."<init>" 8: putstatic #52 // Field Companion:Employee$Companion; 11: return } companion objects
  • 39. enum class Colour { Red, Green, Blue } fun main() { Colour.values().forEach(::println) } Enumerations Red Green Blue
  • 40. public final class Colour extends java.lang.Enum<Colour> { public static final Colour Red; public static final Colour Green; public static final Colour Blue; private static final Colour[] $VALUES; private Colour(); public static Colour[] values(); public static Colour valueOf(String); private static final Colour[] $values(); Enumerations
  • 41. static {}; Code: 0: new #2 // class Colour 3: dup 4: ldc #47 // String Red 6: iconst_0 7: invokespecial #48 // Method "<init>":(String;I)V 10: putstatic #39 // Field Red:Colour; 13: new #2 // class Colour 16: dup 17: ldc #49 // String Green 19: iconst_1 20: invokespecial #48 // Method "<init>":(String;I)V 23: putstatic #42 // Field Green:Colour; Enumerations
  • 42. 26: new #2 // class Colour 30: ldc #50 // String Blue 32: iconst_2 33: invokespecial #48 // Method "<init>":(String;I)V 36: putstatic #45 // Field Blue:Colour; 39: invokestatic #52 // Method $values:()[Colour; 42: putstatic #22 // Field $VALUES:[Colour; 45: return } Enumerations
  • 44. data class Person(val name: String, var age: Int) fun demo(person: Person, action: Person.() -> Unit) = person.apply(action) fun main() { val person = Person("Jane", 25) demo(person) { age += 10 println(this) } } lambdas with receivers Person(name=Jane, age=35)
  • 45. public final class ProgramKt { public static final Person demo( Person, kotlin.jvm.functions.Function1<? super Person, kotlin.Unit> ); Code: ... 21: invokeinterface #24,2 //Function1.invoke:(Object;)Object; ... public static final void main(); Code: ... 13: getstatic #42 // Field ProgramKt$main$1.INSTANCE:ProgramKt$main$1; 16: checkcast #20 // class kotlin/jvm/functions/Function1 19: invokestatic #44 // Method demo:(Person;Function1;)Person; ... lambdas with receivers
  • 46. public interface Function1<P1, R> extends Function<R> { public abstract R invoke(P1); } lambdas with receivers javap -cp kotlin-stdlib-1.5.10.jar -c -p kotlin.jvm.functions.Function1 public interface kotlin.Function<R> { } javap -cp kotlin-stdlib-1.5.10.jar -c -p kotlin.jvm.functions.Function
  • 47. public interface Function2<P1, P2, R> extends Function<R> { public abstract R invoke(P1, P2); } lambdas with receivers javap -cp kotlin-stdlib-1.5.10.jar -c -p kotlin.jvm.functions.Function2 public interface Function3<P1, P2, P3, R> extends Function<R> { public abstract R invoke(P1, P2, P3); } javap -cp kotlin-stdlib-1.5.10.jar -c -p kotlin.jvm.functions.Function3
  • 49. – Do suspending functions actually suspend? – Are they really paused and then resumed? – Let’s use Ktor & Coroutines to investigate – Because that’s the main use case – Note other examples exist (e.g. Arrow) consider suspending functions is it all a lie?
  • 50. – First, we write some entity classes – To represent food and beverages – Second, we write a server – Which provides options for breakfast – Finally, we write a client that suspends – This is the code we will dissasemble let’s order breakfast via a REST endpoint
  • 52. enum class BeverageSize { Small, Medium, Large } enum class BeverageType { Expresso, Americano, CafeAuLait } @Serializable class Beverage(val type: BeverageType, val size: BeverageSize) { fun drink() = println("Drinking a $size $type") } our data model
  • 53. @Serializable class Food( private val name: String, private val servingSize: Int, private val withChocolate: Boolean ) { fun eat() { val type = if(withChocolate) "chocolate" else "plain" println("Eating $servingSize $type $name") } } class Breakfast(private val beverage: Beverage, private val food: Food) { fun consume() { beverage.drink() food.eat() } } our data model
  • 55. fun Application.configureBreakfast() { routing { get("/breakfast/beverage") { call.respond(selectBeverage()) } post("/breakfast/food") { val beverage = call.receive<Beverage>() call.respond(selectFood(beverage)) } } } our server-side
  • 56. fun selectBeverage(): Beverage { fun inFrance() = Locale.getDefault() == FRANCE fun beforeNoon() = LocalTime.now().isBefore(LocalTime.NOON) val type = if (inFrance()) CafeAuLait else Americano val size = if (beforeNoon()) Large else Medium return Beverage(type, size) } fun selectFood(beverage: Beverage): Food { val serving = if (beverage.size == Large) 3 else 2 return if (beverage.type == CafeAuLait) { Food("Croissants", serving, true) } else { Food("Pancakes", serving, false) } } our server-side
  • 58. fun main() = runBlocking { printInDetail("Program starts") val client = buildHttpClient() client.use { val breakfast = orderBreakfast(client) printInDetail("Breakfast ordered") breakfast.consume() } printInDetail("Program ends") } our client [Program starts at 12:21:16 on 1] [Ordering breakfast at 12:21:16 on 24] [Breakfast ordered at 12:21:17 on 1] Drinking a Medium Americano Eating 2 plain Pancakes [Program ends at 12:21:17 on 1]
  • 59. fun printInDetail(item: String) { fun timeNow(): String { val formatter = DateTimeFormatter.ofPattern("HH:mm:ss") return formatter.format(LocalTime.now()) } fun timeAndThread(item: String) = "[$item at ${timeNow()} on ${Thread.currentThread().id}]" println(timeAndThread(item)) } our client
  • 60. private fun buildHttpClient() = HttpClient(CIO) { install(JsonFeature) defaultRequest { host = "0.0.0.0" port = 8080 url { protocol = URLProtocol.HTTP } } } our client
  • 61. suspend fun orderBreakfast( client: HttpClient ): Breakfast = withContext(Dispatchers.IO) { printInDetail("Ordering breakfast") val beverage: Beverage = orderBeverage(client) val food: Food = orderFood(client, beverage) Breakfast(beverage, food) } our client
  • 62. private suspend fun orderFood(it: HttpClient, beverage: Beverage): Food = it.post("/breakfast/food") { body = beverage contentType(ContentType.Application.Json) } private suspend fun orderBeverage(it: HttpClient): Beverage = it.get("/breakfast/beverage") { accept(ContentType.Application.Json) } our client
  • 63. – Note this is a suspending function – Which calls two other suspending functions let’s disassemble ‘orderBreakfast’ to see what lies are found within...
  • 64. public static final Object orderBreakfast(...) { return BuildersKt.withContext(... , ... { ... public final Object invokeSuspend(...) { ... label17: { ... switch(this.label) { case 0: ... case 1: ... case 2: ... default: ... } ... } ... } ... }), ...); } let’s disassemble ‘orderBreakfast’
  • 65. why it’s just a big switch statement! ...nested inside a labelled block
  • 66. understanding suspending functions label17: { Object var4 = IntrinsicsKt.getCOROUTINE_SUSPENDED(); HttpClient var5; switch(this.label) { case 0: ResultKt.throwOnFailure($result); UtilsKt.printInDetail("Ordering breakfast"); var5 = client; this.label = 1; var10000 = ProgramKt.orderBeverage(var5, this); if (var10000 == var4) { return var4; } break; var4 will hold the constant value for signaling suspension we suspend by returning if that’s what the orderBeverage function wants
  • 67. how do suspending functions work? via continuations...
  • 69. understanding suspending functions beverage = (Beverage)var10000; var5 = client; this.L$0 = beverage; this.label = 2; var10000 = ProgramKt.orderFood(var5, beverage, this); if (var10000 == var4) { return var4; } when we have the return value from orderBeverage we store it and set the label to 2 we suspend by returning if that’s what the orderFood function wants
  • 70. understanding suspending functions case 2: beverage = (Beverage)this.L$0; ResultKt.throwOnFailure($result); var10000 = $result; break label17; when we have the return value from orderFood we retrieve the beverage from storage, put the food in var10000 and use a labelled block to exit the switch statement
  • 71. understanding suspending functions public final Object invokeSuspend(@NotNull Object $result) { Object var10000; Beverage beverage; label17: { //switch statement lives here } Food food = (Food)var10000; return new Breakfast(beverage, food); } Once the mechanics of calling the other suspending functions are complete, we can build the final return value from the incremental results
  • 72. – Continuation objects hold labels and intermediate results – A switch statement resumes processing at the correct point – A labelled block short-circuits the switch when we are done suspending functions do not suspend!!! they return and are re-invoked
  • 76. working with desktop compose creating a simple calculator – Compose is implemented as a DSL – But goes beyond a purely Internal DSL – A compiler plugin is required – To generate supporting infrastructure – This implies we are being deceived – Let’s look at a sample application...
  • 77. fun main() = application { Window(...) { val savedTotal = remember { mutableStateOf(0) } val displayedTotal = remember { mutableStateOf(0) } val operationOngoing = remember { mutableStateOf(Operation.None) } val operationJustChanged = remember { mutableStateOf(false) } //Event Handlers Omitted InstilTheme { Column { Row { DisplayText(text = "${displayedTotal.value}") } Row { NumberButtonColumn(numberSelected) OperationButtonColumn(operationSelected, clearSelected, equalsSelected) } } } } } building a calculator via compose
  • 78. @Composable fun InstilTheme(content: @Composable () -> Unit) { val colors = MaterialTheme.colors.copy(primary = Color.LightGray) MaterialTheme(content = content, colors = colors) } @Composable fun DisplayText(text: String) = Text( text = text, style = TextStyle(color = Color.Black, fontSize = 28.sp), modifier = Modifier.padding(all = 10.dp) ) building a calculator via compose
  • 79. @Composable fun NumberButton(onClick: () -> Unit, number: Int) = Button( onClick = onClick, modifier = Modifier.padding(all = 5.dp) ) { Text( number.toString(), style = TextStyle(color = Color.Black, fontSize = 18.sp) ) } @Composable fun NumberButtonRow(range: IntRange, onClick: (Int) -> Unit) = Row { range.forEach { num -> NumberButton(onClick = { onClick(num) }, number = num) } } building a calculator via compose
  • 80. @Composable fun NumberButtonColumn(onClick: (Int) -> Unit) = Column { NumberButtonRow(1..3, onClick) NumberButtonRow(4..6, onClick) NumberButtonRow(7..9, onClick) NumberButtonRow(0..0, onClick) } building a calculator via compose
  • 81. @Composable fun OperationButton(onClick: () -> Unit, label: String) = Button( onClick = onClick, modifier = Modifier.padding(all = 2.dp) ) { Text( label, style = TextStyle(color = Color.Black, fontSize = 14.sp) ) } building a calculator via compose
  • 82. @Composable fun OperationButtonColumn( onSelect: (Operation) -> Unit, onClear: () -> Unit, onEquals: () -> Unit ) = Column { listOf( { onSelect(Add) } to "+", { onSelect(Subtract) } to "-", { onSelect(Multiply) } to "*", { onSelect(Divide) } to "/", onClear to "Clear", onEquals to "=" ).forEach { OperationButton(onClick = it.first, label = it.second) } } building a calculator via compose
  • 83. @Composable fun DisplayText(text: String) = Text( text = text, style = TextStyle(color = Color.Black, fontSize = 28.sp), modifier = Modifier.padding(all = 10.dp) ) public static final void DisplayText(String, Composer, int); Code: 0: aload_0 // Lots and lots of bytecode... 791: return decompiling the calculator
  • 84. – Every compose functions takes: – An object of type composer – A unique integer value – The composer builds the logical tree of widgets – The integer uniquely identifies an instance of a widget decompiling the calculator the additional parameters
  • 85. public final class CalculatorKt { public static final void InstilTheme( Function2<? super Composer, ? super Integer, Unit>, Composer, int ); public static final void DisplayText( String, Composer, int ); public static final void NumberButton( Function0<Unit>, int, Composer, int ); decompiling the calculator
  • 86. public static final void OperationButton( Function0<Unit>, String, Composer, int ); public static final void OperationButtonColumn( Function1<? super Operation, Unit>, Function0<Unit>, Function0<Unit>, Composer, int ); decompiling the calculator
  • 87. public static final void NumberButtonRow( IntRange, Function1<? super Integer, Unit>, Composer, int ); public static final void NumberButtonColumn( Function1<? super Integer, Unit>, Composer, int ); public static final void main(); public static void main(String[]); } decompiling the calculator
  • 88. – Composable functions support Positional Memoization – Memory of how they were called at each point on the graph – They can also be re-invoked at any time (Recomposition) – This is accomplished via a Gap Buffer / Slot Table decompiling the calculator groups and the slot table
  • 89. – On every call we insert a new group into the table – The group is identified by the integer parameter – Nested components add groups for child components – We walk the graph depth first to build a linear structure decompiling the calculator groups and the slot table Group (123) Group (456) Group (789)
  • 90. public static final void DisplayText(String, Composer, int); Code: 7: ldc #110 // int 1244737340 9: invokeinterface #25, 2 // Composer.startRestartGroup:(I) ... 33: invokeinterface #37, 2 // Composer.changed:(Object) ... 58: invokeinterface #41, 1 // Composer.getSkipping:() ... 167: invokeinterface #79, 1 // Composer.skipToGroupEnd:()V ... 173: invokeinterface #83, 1 // Composer.endRestartGroup:() ... 202: invokeinterface #97, 2 // ScopeUpdateScope.updateScope:(Function2) 207: return decompiling the calculator
  • 93. – They provide advanced features – They provide consistency across all the platforms the language supports – They let us work at higher levels of abstraction (with certainty) – They get us home by 5pm  the lies are everywhere! ...and that’s a good thing