Slide 1

Slide 1 text

Tips for Kotlin Developers

Slide 2

Slide 2 text

Agenda • Concerns & Cost • Kotlin Tips • Now what

Slide 3

Slide 3 text

Concerns

Slide 4

Slide 4 text

Hard • Method count [Use Proguard] • APK size • Before Proguard : 895 KB (JAR) / 1119 KB (DEX) (6317 methods). • After Proguard : • Build Time [Gradle-Profiler] • Static Analysis, • KLint, detekt • Android Lint in AS 3.0 • Build Options • Parallel 16838 -> 16924 380 KB for debug, 15 KB for release Incremental , Instant Run

Slide 5

Slide 5 text

Soft • Learning Curve • Best Practice • Code Review • Hiring < 1W Kotlin Bytecode
 Convention Leader / Responsibility

Slide 6

Slide 6 text

Users • BaseCamp • Pintrest • Uber • IntelliJ • Corda

Slide 7

Slide 7 text

Cost

Slide 8

Slide 8 text

Hidden Cost [on ART] [on HotSpot] • Higher-order functions and Lambda expressions • Companion Object • Local Functions • Null safety • Indirect access to Range • Ranges (local, non-primitive types) • Ranges (iteration with explicit step) • Use of indices on custom collection • Varargs + Spread Operator • Delegate Properties (10%) • Ranges (forEach function)

Slide 9

Slide 9 text

blog.jetbrains.com/kotlin/ • It keeps improving :)

Slide 10

Slide 10 text

Idioms

Slide 11

Slide 11 text

Kotlin Bytecode

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Property and Field

Slide 14

Slide 14 text

Property fun main(args: Array) {
 println(Order().amount)
 }
 
 class Order {
 var amount = 0
 get() {
 if (amount > 100) {
 return amount
 } else {
 return 0
 }
 }
 }

Slide 15

Slide 15 text

Backing Field fun main(args: Array) {
 println(Order().amount)
 }
 
 class Order {
 var amount = 0
 get() {
 if (field > 100) {
 return amount
 } else {
 return 0
 }
 }
 }

Slide 16

Slide 16 text

Object

Slide 17

Slide 17 text

Object class Service { object Factory { fun create() = Service() } } fun test() { val service = Service.Factory.create() }

Slide 18

Slide 18 text

Companion Object class Service { companion object Factory { fun create() = Service() } } fun test() { val service = Service.create() }

Slide 19

Slide 19 text

Companion or not? • companion object must have a company :) • companion object can skip it’s name when called. • Each class can at most has one companion object.

Slide 20

Slide 20 text

Static Method

Slide 21

Slide 21 text

Package Level Function // File : Component.kt package com.example class Service fun create() = Service() // Use in kotlin in another package fun main(args: Array) { var s: Service? = com.exmaple.create() } // Use in Java public static final void main(@NotNull String[] args) { Service s = com.exmaple.ComponentKt.create(); } each file will generate a separate class

Slide 22

Slide 22 text

Factory class Service private constructor(){ private var endpoint: String = "dev.api.com" companion object { fun create() = Service().apply { endpoint = "prod.api.com" } } } private member access

Slide 23

Slide 23 text

Companion Object class MyClass {
 
 companion object {
 private val TAG = "TAG"
 }
 
 fun helloWorld() {
 println(TAG)
 }
 }

Slide 24

Slide 24 text

class MyClass {
 
 companion object {
 private val TAG = "TAG"
 }
 
 fun helloWorld() {
 println(TAG)
 }
 } public final class MyClass {
 
 public static final class Companion {
 private final String getTAG() {
 return MyClass.TAG;
 }
 
 private Companion() { }
 } private static final String TAG = "TAG";
 public static final MyClass.Companion Companion = new MyClass.Companion(….);
 
 public final void helloWorld() {
 String var1 = Companion.getTAG();
 System.out.println(var1);
 }
 }

Slide 25

Slide 25 text

class MyClass {
 
 companion object {
 private val TAG = "TAG"
 }
 
 fun helloWorld() {
 println(TAG)
 }
 } public final class MyClass {
 
 public static final class Companion {
 private final String getTAG() {
 return MyClass.TAG;
 }
 
 private Companion() { }
 } private static final String TAG = "TAG";
 public static final MyClass.Companion Companion = new MyClass.Companion(….);
 
 public final void helloWorld() {
 String var1 = Companion.getTAG();
 System.out.println(var1);
 }
 } extra method call

Slide 26

Slide 26 text

Companion Object class MyClass {
 
 companion object {
 const val TAG = "TAG"
 }
 
 fun helloWorld() {
 println(TAG)
 }
 } public final class MyClass {
 
 public static final class Companion {
 private final String getTAG() {
 return MyClass.TAG;
 }
 
 private Companion() { }
 } private static final String TAG = "TAG";
 public static final MyClass.Companion Companion = MyClass.Companion(….);
 
 public final void helloWorld() {
 String var1 = "TAG";
 System.out.println(var1);
 }
 }

Slide 27

Slide 27 text

Lambda

Slide 28

Slide 28 text

Lambda fun higher(op: () -> Unit) {
 println("start")
 op()
 println("end")
 }
 
 fun main(args: Array) {
 higher({ println("HI") })
 } Let’s look at the client side

Slide 29

Slide 29 text

Lambda - decompile public static final void higher(@NotNull Function0 op) {
 Intrinsics.checkParameterIsNotNull(op, "op");
 String var1 = "start";
 System.out.println(var1);
 op.invoke();
 var1 = "end";
 System.out.println(var1);
 }
 
 public static final void main(@NotNull String[] args) {
 Intrinsics.checkParameterIsNotNull(args, "args");
 higher((Function0)null.INSTANCE);
 } extra object extra method call

Slide 30

Slide 30 text

Lambda inline fun higher(op: () -> Unit) {
 println("start")
 op()
 println("end")
 }
 
 fun main(args: Array) {
 higher({ println("HI") })
 }

Slide 31

Slide 31 text

Lambda - inline public static final void higher(@NotNull Function0 op) {
 Intrinsics.checkParameterIsNotNull(op, "op");
 String var2 = "start";
 System.out.println(var2);
 op.invoke();
 var2 = "end";
 System.out.println(var2);
 }
 
 public static final void main(@NotNull String[] args) {
 Intrinsics.checkParameterIsNotNull(args, "args");
 String var1 = "start";
 System.out.println(var1);
 String var2 = "HI";
 System.out.println(var2);
 var1 = "end";
 System.out.println(var1);
 } Copy Paste

Slide 32

Slide 32 text

Reified Generics // Kotlin inline fun isA(value: Any) = value is T fun main(args: Array) { println(isA("abc")) } // Java public static final void main(@NotNull String[] args) { Object value$iv = "abc"; boolean var3 = value$iv instanceof String; System.out.println(var3); }

Slide 33

Slide 33 text

infix annotation infix fun String.shouldBeEqualTo(value: String) = this == value
 
 
 fun main(args: Array) {
 
 val output = "Hello"
 
 output.shouldBeEqualTo("Hello")
 output shouldBeEqualTo "Hello"
 
 } more expressive

Slide 34

Slide 34 text

Return

Slide 35

Slide 35 text

Non-local Returns fun containingFunction() { val numbers = 1..10 numbers.forEach { print("$it ") if (it % 5 == 0) return } println("END") } 1 2 3 4 5

Slide 36

Slide 36 text

Local Returns fun containingFunction4() { val numbers = 1..10 numbers.forEach myLabel@ { print("$it ") if (it % 5 == 0) return@myLabel } println("END") } 1 2 3 4 5 6 7 8 9 10 END

Slide 37

Slide 37 text

Local Returns fun containingFunction4() { val numbers = 1..10 numbers.forEach { print("$it ") if (it % 5 == 0) return@foreach } println("END") } 1 2 3 4 5 6 7 8 9 10 END

Slide 38

Slide 38 text

Local Returns fun containingFunction5() { val numbers = 1..10 numbers.forEach( fun(element) { print("$element ") if (element % 5 == 0) return }) println("END") } anonymous function 1 2 3 4 5 6 7 8 9 10 END

Slide 39

Slide 39 text

Tail Recursion* 
 fun factorial(number: Int): Int {
 when (number) {
 0, 1 -> return 1
 else -> return number * factorial(number - 1)
 }
 }
 
 
 tailrec fun factorialTR(number: Int, accumulator: Int = 1): Int {
 when (number) {
 0 -> return accumulator
 else -> return factorialTR(number - 1, accumulator * number)
 }
 }
 
 
 fun main(args: Array) {
 println(factorial(5))
 println(factorialTR(5))
 }

Slide 40

Slide 40 text

Tail Recursion* public static final int factorial(int number) { switch(number) { case 0: case 1: return 1; default: return number * factorial(number - 1); } } public static final int factorialTR(int number, int accumulator) { while(true) { switch(number) { case 0: return accumulator; default: int var10000 = number - 1; accumulator *= number; number = var10000; } } }

Slide 41

Slide 41 text

.. vs until // Kotlin for (i in 0..width - 1) // Java byte width = 11; 
 int i = 0;
 int var2 = width - 1;
 if(i <= var2) {
 while(i != var2) {
 ++i;
 }
 }
 
 // Kotlin for (i in 0 until width) // Java byte width = 11;
 IntRange var10000 = RangesKt.until(0, width); int i = var10000.getFirst();
 int var2 = var10000.getLast();
 if(i <= var2) {
 while(i != var2) {
 ++i;
 }
 }


Slide 42

Slide 42 text

Delegation

Slide 43

Slide 43 text

Lazy Delegation class LazyProperty { val lazy: Int by lazy { println("Calculate the value") 42 } } fun main(args: Array) { println("--- creation ---") val property = LazyProperty() println("--- first access ---${property.lazy}") println("--- second access ---${property.lazy}") } --- creation --- Calculate the value --- first access ---42 --- second access ---42

Slide 44

Slide 44 text

Observable class Person(val name: String, a: Int, s: Int) { private val observer = { prop: KProperty<*>, old: Int, new: Int -> println("[${prop.name}] $old => $new") } var age by Delegates.observable(a, observer) var salary by Delegates.observable(s, observer) } fun main(args: Array) { val person = Person("Alice", 25, 2000) person.age++ person.salary += 100 } [age] 25 => 26 [salary] 2000 => 2100

Slide 45

Slide 45 text

Observable public class MyActivity : Activity() { private var state: UIState by Delegates.observable(UIState.SIGN_IN_PROMPT) { property, oldValue, newValue ->
 runOnUiThread {
 // Set UI state accordingly……
 when (newValue) {
 UIState.SIGN_IN_PROMPT -> {…}
 UIState.ERROR -> {…}
 UIState.LOADING -> {…}
 UIState.SHOW_DATA -> {…}
 }
 }
 } // state = uiState

Slide 46

Slide 46 text

Standard Library

Slide 47

Slide 47 text

let val list: ArrayList? = ArrayList() var result = list?.let { it.add("A") it.add("B") it.add("C") it.remove("A") it.removeAt(1) print(it) } [B]

Slide 48

Slide 48 text

let val list: ArrayList? = ArrayList() var result = list?.let { it.add("A") it.add("B") it.add("C") it.remove("A") it.removeAt(1) print(it) if (it.size == 0) "end" else true } print(result.toString()) [B] true

Slide 49

Slide 49 text

apply val list: ArrayList? = ArrayList() var result = list?.apply { add("A") add("B") add("C") remove("A") removeAt(1) print(this) } print("size=${result?.size}") [B] size=1 ArrayList?

Slide 50

Slide 50 text

repeat repeat(3, { println("$it "); }) 1 2 3

Slide 51

Slide 51 text

other std-libs • run • with • takeIf • also • takeUnless

Slide 52

Slide 52 text

Design Pattern

Slide 53

Slide 53 text

Singleton object KSingleton { fun foo() {} } fun main(args: Array) { KSingleton.foo() }

Slide 54

Slide 54 text

Delegate class Service { var someProperty: String by ExternalFunctionality() } class ExternalFunctionality { var backingField = "Default" operator fun getValue(s: Service, p: KProperty<*>): String { println("===debug message====") return backingField } operator fun setValue(s: Service, p: KProperty<*>, v: String) { backingField = v } }

Slide 55

Slide 55 text

Builder [type-safe-builder] val result = html { head { title { +"XML encoding with Kotlin" } } body { h1 { +"XML encoding with Kotlin" } a(href = “http://…”) { +"Kotlin" } } } println(result) XML encoding with Kotlin

Kotlin

Slide 56

Slide 56 text

Factory interface Factory { fun create(): T } class A { private constructor() companion object : Factory { override fun create(): A { return A() } } } fun main(args: Array) { val a = A.create() }

Slide 57

Slide 57 text

Tips • Beware of auto boxing 
 class Dog {
 var age = 3
 var weight: Int? = 5
 } public final class Dog {
 private int age = 3;
 @Nullable
 private Integer weight = Integer.valueOf(5);
 }


Slide 58

Slide 58 text

Other tips • For Java library developers : make your SAM-type parameter the last element • Stream vs for loop : IO bound - Stream : CPU bound - for loop better

Slide 59

Slide 59 text

Ktlint[blog] check.dependsOn ‘ktlint’ configurations {
 ktlint
 }
 
 dependencies {
 ktlint 'com.github.shyiko:ktlint:0.9.2'
 } task ktlint(type: JavaExec) {
 main = "com.github.shyiko.ktlint.Main"
 classpath = configurations.ktlint
 args "src/**/*.kt"
 } // $ ./gradlew ktlint run!

Slide 60

Slide 60 text

Deprecated

Slide 61

Slide 61 text

Deprecated

Slide 62

Slide 62 text

Deprecated

Slide 63

Slide 63 text

What’s Next?

Slide 64

Slide 64 text

Coroutines

Slide 65

Slide 65 text

Callback • new Task1().execute() {
 void onComplete() {
 new Task2().execute() {
 void onComplete() {
 new Task3().execute() {
 void onComplete() {
 // doWork()
 }
 }
 }
 }
 }

Slide 66

Slide 66 text

Rx / Promise / Future • task1().then {
 task2()
 }.then() {
 task3()
 }.subscribe {
 updateUI()
 }

Slide 67

Slide 67 text

Coroutine • launch(UI) {
 val r1 = task1()
 val r2 = task2()
 val r3 = task3()
 updateUI(r1.await(), r2.await, r3.await())
 }

Slide 68

Slide 68 text

async / await val time = measureTimeMillis { val one = async(CommonPool) { function1() } val two = async(CommonPool) { function2() } println("Result is ${one.await() + two.await()}") } println("Total time: $time")

Slide 69

Slide 69 text

Thread fun threads() { val jobs = 1..100000 jobs.forEach { Thread() { Thread.sleep(1000L) print(".") }.start() } } Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:714)

Slide 70

Slide 70 text

Coroutine fun coroutines() = runBlocking { val jobs = List(100000) { launch(CommonPool) { delay(1000L) print(".") } } jobs.forEach { it.join() } } …………………………………………………………………………………………………………………

Slide 71

Slide 71 text

Fun Projects

Slide 72

Slide 72 text

Firefox Focus • Privacy • Kotlin Ready! • Contribute :
 on [github]

Slide 73

Slide 73 text

FireFox Data • Sync with your History, Bookmarks, Password • Kotlin Ready! • Contribute
 on [github]

Slide 74

Slide 74 text

Firefox For Android • Secure / Fast • Stay Tune :) • Contribute :
 with [git] on
 [mercurial]

Slide 75

Slide 75 text

News & Resources • Coding Conventions • KotlinConf • Books : Kotlin in Action / Kotlin for Android Developers • Offcial Document • Podcast: Talking Kotlin • Kotlin Native

Slide 76

Slide 76 text

Have Fun!

Slide 77

Slide 77 text