Slide 1

Slide 1 text

Irrational Exuberance: Kotlin Edition @danlew42

Slide 2

Slide 2 text

–Alan Greenspan How do we know when irrational exuberance has unduly escalated asset values?

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

https://www.flickr.com/photos/imuttoo/6066349127

Slide 5

Slide 5 text

https://www.flickr.com/photos/peasap/4063408356

Slide 6

Slide 6 text

Implicit Types fun explicitType(): String { val name: String = "Dan Lew" val number: Int = 42 return name + number } fun implicitType(): String { val name = "Dan Lew" val number = 42 return name + number }

Slide 7

Slide 7 text

Implicit Types fun explicitType(): String { val name: String = "Dan Lew" val number: Int = 42 return name + number } fun implicitType(): String { val name = "Dan Lew" val number = 42 return name + number }

Slide 8

Slide 8 text

Implicit Types public List randomList() { List list = new ArrayList<>(); if (Math.random() > .5) { list.add("Hello!"); } return list; } fun implicitList(): List { val list = mutableListOf() if (Math.random() > .5) { list.add("Hello!") } return list }

Slide 9

Slide 9 text

Implicit Types public List randomList() { List list = new ArrayList<>(); if (Math.random() > .5) { list.add("Hello!"); } return list; } fun implicitList(): List { val list = mutableListOf() if (Math.random() > .5) { list.add("Hello!") } return list }

Slide 10

Slide 10 text

Implicit Types fun whoseTypeIsThis() { val foo = listOf("apples", "bananas", "pears") .map { it to it.length } .filter { it.second == 3 } .associate { it } .toMutableMap() }

Slide 11

Slide 11 text

Expression Functions fun add(one: Int, two: Int): Int { return one + two } fun add(one: Int, two: Int): Int = one + two fun add(one: Int, two: Int) = one + two

Slide 12

Slide 12 text

Expression Functions fun add(one: Int, two: Int): Int { return one + two } fun add(one: Int, two: Int): Int = one + two fun add(one: Int, two: Int) = one + two

Slide 13

Slide 13 text

Expression Functions fun add(one: Int, two: Int): Int { return one + two } fun add(one: Int, two: Int): Int = one + two fun add(one: Int, two: Int) = one + two

Slide 14

Slide 14 text

Expression Functions class Diff(val old: State, val new: State) : DiffUtil.Callback() { override fun getOldListSize() = old.itemCount override fun getNewListSize() = new.itemCount override fun areItemsTheSame(oldItemPos: Int, newItemPos: Int) = old.getItemId(oldItemPos) == new.getItemId(newItemPos) override fun areContentsTheSame(oldItemPos: Int, newItemPos: Int) = old.fields[oldItemPos] == new.fields[newItemPos] }

Slide 15

Slide 15 text

Expression Functions fun wayTooMuch() = listOf("apples", "bananas", "pears") .map { it to it.length } .filter { it.second == 3 } .associate { it } .toMutableMap() fun alsoTooMuch(input: String?, num: Int) = if (input != null) num * (num + 5) / 3 * input.length else num * num + num / num

Slide 16

Slide 16 text

Expression Functions fun wayTooMuch() = listOf("apples", "bananas", "pears") .map { it to it.length } .filter { it.second == 3 } .associate { it } .toMutableMap() fun alsoTooMuch(input: String?, num: Int) = if (input != null) num * (num + 5) / 3 * input.length else num * num + num / num

Slide 17

Slide 17 text

Nullability fun one(input: String) { if (input.length == 5) { // Do something } } fun two(input: String?) { if (input?.length == 5) { // Do something } }

Slide 18

Slide 18 text

Nullability fun one(input: String) { if (input.length == 5) { // Do something } } fun two(input: String?) { if (input?.length == 5) { // Do something } }

Slide 19

Slide 19 text

Nullability fun length(input: String): Int = input.length fun length(input: String?): Int? = input?.length fun length(input: String?): Int { if (input != null) { return input.length } else { return 0 } } fun length(input: String?): Int = input?.length ?: 0

Slide 20

Slide 20 text

Nullability fun length(input: String): Int = input.length fun length(input: String?): Int? = input?.length fun length(input: String?): Int { if (input != null) { return input.length } else { return 0 } } fun length(input: String?): Int = input?.length ?: 0

Slide 21

Slide 21 text

Nullability fun length(input: String): Int = input.length fun length(input: String?): Int? = input?.length fun length(input: String?): Int { if (input != null) { return input.length } else { return 0 } } fun length(input: String?): Int = input?.length ?: 0

Slide 22

Slide 22 text

Nullability fun length(input: String): Int = input.length fun length(input: String?): Int? = input?.length fun length(input: String?): Int { if (input != null) { return input.length } else { return 0 } } fun length(input: String?): Int = input?.length ?: 0

Slide 23

Slide 23 text

Nullability data class Card( val id: String, val name: String, val description: String? )

Slide 24

Slide 24 text

Nullability data class Card( val id: String, val name: String, val description: String? ) • Should I avoid null at all costs?

Slide 25

Slide 25 text

Nullability data class Card( val id: String, val name: String, val description: String? ) • Should I avoid null at all costs? • Compiler assists null usage

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

Nullability class MyFragment : Fragment() { override fun onResume() { super.onResume() val key = context.getString(R.string.google_api_key) } }

Slide 28

Slide 28 text

Nullability val currentContext = context if (currentContext != null) { val key = currentContext.getString(R.string.key) } else { throw IllegalStateException("How?!") } val key = context?.getString(R.string.key) ?: throw IllegalStateException("How?!") val key = checkNotNull(context, { "How?!" }).getString(R.string.key) val key = context!!.getString(R.string.key)

Slide 29

Slide 29 text

Nullability val currentContext = context if (currentContext != null) { val key = currentContext.getString(R.string.key) } else { throw IllegalStateException("How?!") } val key = context?.getString(R.string.key) ?: throw IllegalStateException("How?!") val key = checkNotNull(context, { "How?!" }).getString(R.string.key) val key = context!!.getString(R.string.key)

Slide 30

Slide 30 text

Nullability val currentContext = context if (currentContext != null) { val key = currentContext.getString(R.string.key) } else { throw IllegalStateException("How?!") } val key = context?.getString(R.string.key) ?: throw IllegalStateException("How?!") val key = checkNotNull(context, { "How?!" }).getString(R.string.key) val key = context!!.getString(R.string.key)

Slide 31

Slide 31 text

Nullability val currentContext = context if (currentContext != null) { val key = currentContext.getString(R.string.key) } else { throw IllegalStateException("How?!") } val key = context?.getString(R.string.key) ?: throw IllegalStateException("How?!") val key = checkNotNull(context, { "How?!" }).getString(R.string.key) val key = context!!.getString(R.string.key)

Slide 32

Slide 32 text

Nullability val currentContext = context if (currentContext != null) { val key = currentContext.getString(R.string.key) } else { throw IllegalStateException("How?!") } val key = context?.getString(R.string.key) ?: throw IllegalStateException("How?!") val key = checkNotNull(context, { "How?!" }).getString(R.string.key) val key = context!!.getString(R.string.key)

Slide 33

Slide 33 text

Nullable Primitives • Int -> int fun foo() { var total = 0 for (value in 0..10) { total += bar(value) ?: 0 } } fun bar(value: Int?) = value

Slide 34

Slide 34 text

Nullable Primitives • Int -> int • Int? -> Integer fun foo() { var total = 0 for (value in 0..10) { total += bar(value) ?: 0 } } fun bar(value: Int?) = value

Slide 35

Slide 35 text

Nullable Primitives • Int -> int • Int? -> Integer fun foo() { var total = 0 for (value in 0..10) { total += bar(value) ?: 0 } } fun bar(value: Int?) = value

Slide 36

Slide 36 text

lateinit class MyActivity : Activity() { var centerView: TextView? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home) centerView = findViewById(R.id.center_view) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putCharSequence("key", centerView?.text ?: "") } }

Slide 37

Slide 37 text

lateinit class MyActivity : Activity() { var centerView: TextView? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home) centerView = findViewById(R.id.center_view) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putCharSequence("key", centerView?.text ?: "") } }

Slide 38

Slide 38 text

lateinit class MyActivity : Activity() { var centerView: TextView? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home) centerView = findViewById(R.id.center_view) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putCharSequence("key", centerView?.text ?: "") } }

Slide 39

Slide 39 text

lateinit class MyActivity : Activity() { var centerView: TextView? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home) centerView = findViewById(R.id.center_view) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putCharSequence("key", centerView?.text ?: "") } }

Slide 40

Slide 40 text

lateinit class MyActivity : Activity() { lateinit var centerView: TextView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home) centerView = findViewById(R.id.center_view) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putCharSequence("key", centerView.text) } }

Slide 41

Slide 41 text

lateinit class MyActivity : Activity() { lateinit var centerView: TextView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home) centerView = findViewById(R.id.center_view) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putCharSequence("key", centerView.text) } }

Slide 42

Slide 42 text

lateinit class MyActivity : Activity() { lateinit var centerView: TextView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home) // centerView = findViewById(R.id.center_view) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putCharSequence("key", centerView.text) } }

Slide 43

Slide 43 text

Companion Objects • “Where are my static methods?!” • “Where are my constants?!” • Common answer: companion objects • Singletons associated with a class

Slide 44

Slide 44 text

Companion Objects class CompanionObjects { companion object { @JvmStatic fun add(one: Int, two: Int) = one + two const val TAG = "Hello" } }

Slide 45

Slide 45 text

Companion Objects // Accessible anywhere fun functionsCanAlsoBeHere() { } // Accessible via SomeObject object SomeObject { @JvmStatic fun functionInOtherObjects() { } }

Slide 46

Slide 46 text

Companion Objects // Accessible anywhere fun functionsCanAlsoBeHere() { } // Accessible via SomeObject object SomeObject { @JvmStatic fun functionInOtherObjects() { } }

Slide 47

Slide 47 text

Lifted Statements fun saySomething(intro: Boolean): String { if (intro) { return "Hello" } else { return "Goodbye" } } fun saySomething(intro: Boolean): String { return if (intro) { "Hello" } else { "Goodbye" } } fun saySomething(intro: Boolean): String { return if (intro) "Hello" else "Goodbye" }

Slide 48

Slide 48 text

Lifted Statements fun saySomething(intro: Boolean): String { if (intro) { return "Hello" } else { return "Goodbye" } } fun saySomething(intro: Boolean): String { return if (intro) { "Hello" } else { "Goodbye" } } fun saySomething(intro: Boolean): String { return if (intro) "Hello" else "Goodbye" }

Slide 49

Slide 49 text

Lifted Statements fun saySomething(intro: Boolean): String { if (intro) { return "Hello" } else { return "Goodbye" } } fun saySomething(intro: Boolean): String { return if (intro) { "Hello" } else { "Goodbye" } } fun saySomething(intro: Boolean): String { return if (intro) "Hello" else "Goodbye" }

Slide 50

Slide 50 text

Lifted Statements fun complexLift(list: List): Int { if (list.size < 10) { return list .filter { it > 10 } .maxBy { it }!! } else { val folded = list .drop(10) .filter { it < -10 } .foldRight(1, { i, acc -> i * acc }) val otherThing = list.size % 15 return folded * otherThing } }

Slide 51

Slide 51 text

Lifted Statements fun complexLift(list: List): Int { return if (list.size < 10) { list .filter { it > 10 } .maxBy { it }!! } else { val folded = list .drop(10) .filter { it < -10 } .foldRight(1, { i, acc -> i * acc }) val otherThing = list.size % 15 folded * otherThing } }

Slide 52

Slide 52 text

when enum class Model { CARD, BOARD, LIST, MEMBER } fun endpoint(model: Model): String { return when(model) { Model.BOARD -> "/1/board" Model.LIST -> "/1/list" Model.CARD -> "/1/card" Model.MEMBER -> "/1/member" } }

Slide 53

Slide 53 text

when fun size(num: Int): String { return when (num) { in 0..99 -> "small" in 100..999 -> "medium" in 1000..9999 -> "large" in 10000..Int.MAX_VALUE -> "gigantic" else -> "negative" } }

Slide 54

Slide 54 text

when fun groupType(model: Model): Int { return when (model) { Model.CARD -> 1 else -> 2 } } fun groupType(model: Model): Int { return if (model == Model.CARD) 1 else 2 }

Slide 55

Slide 55 text

when fun groupType(model: Model): Int { return when (model) { Model.CARD -> 1 else -> 2 } } fun groupType(model: Model): Int { return if (model == Model.CARD) 1 else 2 }

Slide 56

Slide 56 text

Standard Functions • let • run • with • apply • also

Slide 57

Slide 57 text

Standard Functions fun T.let(block: (T) -> R): R fun run(block: () -> R): R fun T.run(block: T.() -> R): R fun with(receiver: T, block: T.() -> R): R fun T.apply(block: T.() -> Unit): T fun T.also(block: (T) -> Unit): T

Slide 58

Slide 58 text

Let class Container { var message: String? = null fun messageLength(): Int { if (message != null) { return message.length } return 0 } }

Slide 59

Slide 59 text

Let class Container { var message: String? = null fun messageLength(): Int { val currMsg = message if (currMsg != null) { return currMsg.length } return 0 } }

Slide 60

Slide 60 text

Let class Container { var message: String? = null fun messageLength(): Int { val currMsg = message if (currMsg != null) { return currMsg.length } return 0 } }

Slide 61

Slide 61 text

Let class Container { var message: String? = null fun messageLength(): Int { val currMsg = message if (currMsg != null) { return currMsg.length } return 0 } }

Slide 62

Slide 62 text

Let class Container { var message: String? = null fun messageLength(): Int { message?.let { currMsg -> return currMsg.length } return 0 } }

Slide 63

Slide 63 text

Let class Container { var message: String? = null fun messageLength(): Int { message?.let { currMsg -> return currMsg.length } return 0 } }

Slide 64

Slide 64 text

Let class Container { var message: String? = null fun messageLength() = message?.length ?: 0 }

Slide 65

Slide 65 text

Inline Functions // Original source code fun foo() { bar() } inline fun bar() { println("Hello, world!") } // Compiled code fun foo() { println("Hello, world!") }

Slide 66

Slide 66 text

Inline Functions // Original source code fun foo() { bar() } inline fun bar() { println("Hello, world!") } // Compiled code fun foo() { println("Hello, world!") }

Slide 67

Slide 67 text

Inline Functions • Java is optimized for method calls • Inline only when… • Avoiding object creation • Using reified types • You can prove there’s a substantial gain from inlining a function

Slide 68

Slide 68 text

Thanks! • @danlew42 • danlew.net