Slide 1

Slide 1 text

Jake Wharton 10 Kotlin Tricks In 10(ish) Minutes

Slide 2

Slide 2 text

Why Kotlin?

Slide 3

Slide 3 text

Why Kotlin? val firstName: String = "Jake"
 val lastName: String? = null

Slide 4

Slide 4 text

Why Kotlin? val firstName = "Jake"
 val lastName: String? = null

Slide 5

Slide 5 text

Why Kotlin? class User {
 public String getName() {
 // ...
 }
 public void setName(String name) {
 // ...
 }
 } // ^^^ Java

Slide 6

Slide 6 text

Why Kotlin? class User {
 public String getName() {
 // ...
 }X
 public void setName(String name) {
 // ...
 }Y
 }Z // ^^^ Java vvv Kotlin val user = User()
 println("Name is " + user.name)

Slide 7

Slide 7 text

Why Kotlin? class User {
 public String getName() {
 // ...
 }X
 public void setName(String name) {
 // ...
 }Y
 }Z // ^^^ Java vvv Kotlin val user = User()
 println("Name is ${user.name}")

Slide 8

Slide 8 text

Why Kotlin? class User {
 public String getName() {
 // ...
 }X
 public void setName(String name) {
 // ...
 }Y
 }Z // ^^^ Java vvv Kotlin val user = User()
 println("Name is $user")

Slide 9

Slide 9 text

Why Kotlin? val user = User()

Slide 10

Slide 10 text

Why Kotlin? val user = User()
 user = User()
 
 var currentUser = User()
 currentUser = User()

Slide 11

Slide 11 text

Why Kotlin? fun Date.isTuesday(): Boolean {
 return day == 2
 }

Slide 12

Slide 12 text

Why Kotlin? fun Date.isTuesday(): Boolean {
 return day == 2
 } val epoch = Date(1970, 0, 0)
 if (epoch.isTuesday()) {
 println("The epoch was a tuesday.")
 } else {
 println("The epoch was not a tuesday.")
 }

Slide 13

Slide 13 text

Why Kotlin? val executor = Executors.newSingleThreadExecutor();
 executor.execute { println("Background thread!") }

Slide 14

Slide 14 text

Why Kotlin? fun List.filter(predicate: (T) -> Boolean): List {
 // ...
 }

Slide 15

Slide 15 text

Why Kotlin? fun List.filter(predicate: (T) -> Boolean): List {
 // ...
 }X

Slide 16

Slide 16 text

Why Kotlin? inline fun List.filter(predicate: (T) -> Boolean): List {
 // ...
 }X

Slide 17

Slide 17 text

Why Kotlin? inline fun List.filter(predicate: (T) -> Boolean): List {
 // ...
 }

Slide 18

Slide 18 text

Why Kotlin? data class User(val firstName: String, val lastName: String)

Slide 19

Slide 19 text

Why Kotlin? http://jakes.link/why-kotlin

Slide 20

Slide 20 text

#01 Explosive Placeholders

Slide 21

Slide 21 text

#01 Explosive Placeholders class Test : Runnable {
 override fun run() {
 // TODO doSomethingElse()?
 }B
 }A

Slide 22

Slide 22 text

#01 Explosive Placeholders class Test : Runnable {Y
 override fun run() {Z
 if (something()) {
 doSomething()
 } else {
 // TODO doSomethingElse()?
 }C
 }B
 }A

Slide 23

Slide 23 text

#01 Explosive Placeholders class Test : Runnable {Y
 override fun run() {Z
 if (something()) {
 doSomething()
 } else {
 // TODO doSomethingElse()?
 }C
 }B
 }A

Slide 24

Slide 24 text

#01 Explosive Placeholders class Test : Callable {Y
 override fun call(): String {Z
 if (something()) {
 return doSomething()
 } else {
 // TODO return doSomethingElse()?
 }C
 }B
 }A Runnable
 run

Slide 25

Slide 25 text

#01 Explosive Placeholders class Test : Callable {Y
 override fun call(): String {Z
 if (something()) {
 return doSomething()
 } else {
 // TODO return doSomethingElse()?
 }C
 }B
 }A Runnable
 run

Slide 26

Slide 26 text

#01 Explosive Placeholders class Test : Callable {
 override fun call(): String {
 if (something()) {
 return doSomething()
 } else {
 throw UnsupportedOperationException("TODO doSomethingElse()?")
 }C
 }B
 }A 
 
 
 
 
 // return

Slide 27

Slide 27 text

#01 Explosive Placeholders class Test : Callable {
 override fun call(): String {
 if (something()) {
 return doSomething()
 } else {
 TODO("doSomethingElse()?")
 }C
 }B
 }A

Slide 28

Slide 28 text

#01 Explosive Placeholders class Test : Callable {
 override fun call(): String {
 if (something()) {
 return doSomething()
 } else {
 TODO("doSomethingElse()?")
 }C
 }B
 }A

Slide 29

Slide 29 text

#02 Semantic Validation

Slide 30

Slide 30 text

#02 Semantic Validation static String join(String sep, List strings) {
 // ...
 }Z

Slide 31

Slide 31 text

#02 Semantic Validation static String join(String sep, List strings) {
 if (sep == null) throw new NullPointerException("sep == null");
 if (strings == null) throw new NullPointerException("strings == null"); 
 // ...
 }Z

Slide 32

Slide 32 text

#02 Semantic Validation static String join(String sep, List strings) {
 if (sep == null) throw new NullPointerException("sep == null");
 if (sep.length() < 2) { throw new IllegalArgumentException("sep.length() < 2: " + sep); }Y
 if (strings == null) throw new NullPointerException("strings == null"); 
 // ...
 }Z

Slide 33

Slide 33 text

#02 Semantic Validation static String join(String sep, List strings) {
 Preconditions.checkNotNull(sep, "sep == null");
 if (sep.length() < 2) {
 throw new IllegalArgumentException("sep.length() < 2: " + sep);
 }Y
 Preconditions.checkNotNull(strings, "strings == null");
 
 // ...
 }Z 
 if == null) throw new NullPointerException(
 
 if == null) throw new NullPointerException(

Slide 34

Slide 34 text

#02 Semantic Validation static String join(String sep, List strings) {
 Preconditions.checkNotNull(sep, "sep == null");
 Preconditions.checkArgument(sep.length() < 2, "sep.length() < 2: " + sep);
 Preconditions.checkNotNull(strings, "strings == null");
 
 // ...
 }Z 
 
 if ) {
 throw new IllegalArgumentException(
 }Y

Slide 35

Slide 35 text

#02 Semantic Validation static String join(String sep, List strings) {
 Preconditions.checkNotNull(sep, "sep == null");
 Preconditions.checkArgument(sep.length() < 2, "sep.length() < 2: " + sep);
 Preconditions.checkNotNull(strings, "strings == null");
 
 // ...
 }Z 
 
 if ) {
 throw new IllegalArgumentException(
 }Y

Slide 36

Slide 36 text

#02 Semantic Validation fun join(sep: String, strings: List): String {
 Preconditions.checkArgument(sep.length < 2, "sep.length < 2: " + sep)
 // ...
 }Z static 
 Preconditions.checkNotNull(sep, "sep == null");
 ;
 Preconditions.checkNotNull(strings, "strings == null");

Slide 37

Slide 37 text

#02 Semantic Validation fun join(sep: String, strings: List): String {
 require(sep.length < 2) { "sep.length < 2: " + sep }
 // ...
 }Z 
 Preconditions.checkArgument , )

Slide 38

Slide 38 text

#02 Semantic Validation fun join(sep: String, strings: List): String {
 require(sep.length < 2) { "sep.length < 2: " + sep }
 // ...
 }Z

Slide 39

Slide 39 text

#02 Semantic Validation fun join(sep: String, strings: List): String {
 require(sep.length < 2) { "sep.length < 2: " + sep }
 // ...
 }Z 
 Preconditions.checkArgument , )

Slide 40

Slide 40 text

#02 Semantic Validation fun join(sep: String, strings: List): String {
 if (sep.length < 2) { throw IllegalArgumentException("sep.length < 2: " + sep) }
 // ...
 }Z 
 require ) { }

Slide 41

Slide 41 text

#02 Semantic Validation // throws IllegalArgumentException require(value: Boolean) require(value: Boolean, lazyMessage: () -> Any) requireNotNull(value: T?): T requireNotNull(value: T?, lazyMessage: () -> Any): T // throws IllegalStateException check(value: Boolean) check(value: Boolean, lazyMessage: () -> Any) checkNotNull(value: T?): T checkNotNull(value: T?, lazyMessage: () -> Any): T // throws AssertionError assert(value: Boolean) assert(value: Boolean, lazyMessage: () -> Any)

Slide 42

Slide 42 text

#03 Anything and Nothing

Slide 43

Slide 43 text

#03 Anything and Nothing Runnable

Slide 44

Slide 44 text

#03 Anything and Nothing Runnable Any

Slide 45

Slide 45 text

#03 Anything and Nothing Runnable Int Any

Slide 46

Slide 46 text

#03 Anything and Nothing Runnable Int Any Nothing

Slide 47

Slide 47 text

#03 Anything and Nothing fun printName(user: User?) {
 val name = user?.name ?: throw IllegalArgumentException("User was null")
 println("Name is $name.")
 }

Slide 48

Slide 48 text

#03 Anything and Nothing fun printName(user: User?) {
 val name = user?.name ?: throw IllegalArgumentException("User was null")
 println("Name is $name.")
 }Z

Slide 49

Slide 49 text

#03 Anything and Nothing fun printName(user: User?) {
 val name = user?.name ?: throw IllegalArgumentException("User was null")
 println("Name is $name.")
 }Z

Slide 50

Slide 50 text

#03 Anything and Nothing fun printName(user: User?) {
 val name = user?.name ?: throw IllegalArgumentException("User was null")
 println("Name is $name.")
 }Z

Slide 51

Slide 51 text

#03 Anything and Nothing fun printName(user: User?) {
 val name = user?.name ?: throw IllegalArgumentException("User was null")
 println("Name is $name.")
 }Z

Slide 52

Slide 52 text

#03 Anything and Nothing fun printName(user: User?) {
 if (user != null) {
 println("Name is ${user.name}.")
 }Y
 throw IllegalArgumentException("User was null")
 }Z 
 val name = ?.name ?:

Slide 53

Slide 53 text

#03 Anything and Nothing fun printName(user: User?) {
 if (user != null) {
 println("Name is ${user.name}.")
 }Y
 throw IllegalArgumentException("User was null")
 }Z

Slide 54

Slide 54 text

#03 Anything and Nothing fun printName(user: User?) {
 if (user != null) {
 println("Name is ${user.name}.")
 }Y
 throw IllegalArgumentException("User was null")
 println("A user has no name.")
 }Z

Slide 55

Slide 55 text

#03 Anything and Nothing fun runServer(serverSocket: ServerSocket) {
 while (true) {
 handleSocket(serverSocket.accept())
 }
 }

Slide 56

Slide 56 text

#03 Anything and Nothing fun runServer(serverSocket: ServerSocket) {X
 while (true) {
 handleSocket(serverSocket.accept())
 }Y
 }Z runServer(ServerSocket(80))
 println("Running!")

Slide 57

Slide 57 text

#03 Anything and Nothing fun runServer(serverSocket: ServerSocket): Nothing {X
 while (true) {
 handleSocket(serverSocket.accept())
 }Y
 }Z runServer(ServerSocket(80))
 println("Running!")

Slide 58

Slide 58 text

#03 Anything and Nothing fun runServer(serverSocket: ServerSocket): Nothing {
 while (true) {
 handleSocket(serverSocket.accept())
 }
 } runServer(ServerSocket(80))
 println("Running!")

Slide 59

Slide 59 text

#04 Let

Slide 60

Slide 60 text

#04 Let val user: User? = null
 
 if (user != null) {X
 // user not null
 }X

Slide 61

Slide 61 text

#04 Let val user: User? = null
 
 user?.let {X
 // it == user not null
 }X 
 
 if ( != null)

Slide 62

Slide 62 text

#04 Let var user: User? = null
 
 user?.let { 
 // it == user not null, only read once!
 }X

Slide 63

Slide 63 text

#04 Let class Foo {
 @Volatile var user: User? = null
 
 fun doSomething() {
 user?.let { user ->
 // user not null, only read once!
 }X
 }Y
 }Z 
 
 
 it ==

Slide 64

Slide 64 text

#04 Let class Foo {
 @Volatile var user: User? = null
 
 fun doSomething() {
 user?.apply {
 // user not null, only read once!
 }X
 }Y
 }Z 
 
 
 
 let

Slide 65

Slide 65 text

#04 Let class Foo {
 @Volatile var user: User? = null
 
 fun doSomething() {
 user?.run {
 // user not null, only read once!
 }X
 }Y
 }Z

Slide 66

Slide 66 text

#04 Let val user: User? = null
 
 someMethod().let { result ->
 // use result multiple times
 }X

Slide 67

Slide 67 text

#05 Multiline String Literals

Slide 68

Slide 68 text

#05 Multiline String Literals val string = "foo"Z

Slide 69

Slide 69 text

#05 Multiline String Literals val string = "foo\nbar\nbaz"Z

Slide 70

Slide 70 text

#05 Multiline String Literals val string = "foo\n" + "bar\n" + "baz"Z

Slide 71

Slide 71 text

#05 Multiline String Literals val string = """foo bar baz"""Z

Slide 72

Slide 72 text

#05 Multiline String Literals val string = """
 foo
 bar
 baz""".trimIndent()

Slide 73

Slide 73 text

#05 Multiline String Literals val string = """
 foo
 bar
 baz""".trimIndent() 
 
 
 Margin

Slide 74

Slide 74 text

#05 Multiline String Literals val string = """|foo
 1|bar
 2|baz""".trimMargin() 
 
 Indent

Slide 75

Slide 75 text

#05 Multiline String Literals val foo = "FOO!"
 val bar = "BAR!"
 val baz = "BAZ!"
 
 val string = """|$foo
 1|$bar
 2|$baz""".trimMargin()

Slide 76

Slide 76 text

#06 Lazy but Speedy

Slide 77

Slide 77 text

#06 Lazy but Speedy class NamePrinter(val firstName: String, val lastName: String) {
 }Z

Slide 78

Slide 78 text

#06 Lazy but Speedy class NamePrinter(val firstName: String, val lastName: String) {
 fun printName() {
 println("$firstName $lastName")
 }Y
 }Z

Slide 79

Slide 79 text

#06 Lazy but Speedy class NamePrinter(val firstName: String, val lastName: String) {
 var fullName: String? = null
 
 fun printName() {
 if (fullName == null) {
 fullName = "$firstName $lastName"
 }X
 println(fullName)
 }Y
 }Z

Slide 80

Slide 80 text

#06 Lazy but Speedy class NamePrinter(val fullName: Lazy) {
 fun printName() {
 println(fullName.get())
 }Y
 }Z @Module
 class NameModule(val firstName: String, val lastName: String) {
 @Provides fun provideFullName() = "$firstName $lastName"
 } 
 var ? = null
 
 
 if (fullName == null) {
 fullName
 


Slide 81

Slide 81 text

#06 Lazy but Speedy class NamePrinter(val firstName: String, val lastName: String) {
 var fullName: String? = null
 
 fun printName() {
 if (fullName == null) {
 fullName = "$firstName $lastName"
 }X
 println(fullName)
 }Y
 }Z

Slide 82

Slide 82 text

#06 Lazy but Speedy class NamePrinter(val firstName: String, val lastName: String) {
 val fullName: String by lazy { "$firstName $lastName" }X
 
 fun printName() {
 println(fullName)
 }Y
 }Z 
 r ? = null
 
 
 if (fullName == null) {
 fullName =
 }X

Slide 83

Slide 83 text

#06 Lazy but Speedy class NamePrinter(val firstName: String, val lastName: String) {
 val fullName: String by lazy { "$firstName $lastName" }X
 
 fun printName() {
 println(fullName)
 }Y
 }Z

Slide 84

Slide 84 text

#06 Lazy but Speedy import kotlin.LazyThreadSafetyMode.NONE
 
 class NamePrinter(val firstName: String, val lastName: String) {
 val fullName: String by lazy(NONE) { "$firstName $lastName" }X
 
 fun printName() {
 println(fullName)
 }Y
 }Z

Slide 85

Slide 85 text

#07 Code Block Measurement

Slide 86

Slide 86 text

#07 Code Block Measurement val helloStart = System.currentTimeMillis()
 println("Hello, world!")
 val helloTook = System.currentTimeMillis() - helloStart
 println("Saying 'hello' took ${helloTook}ms")

Slide 87

Slide 87 text

#07 Code Block Measurement val helloTook = measureTimeMillis {
 println("Hello, world!")
 }X
 
 println("Saying 'hello' took ${helloTook}ms") val helloStart = System.currentTimeMillis()
 
 System.currentTimeMillis() - helloStart

Slide 88

Slide 88 text

#07 Code Block Measurement val helloTook = measureTimeNanos {
 println("Hello, world!")
 }X
 
 println("Saying 'hello'Ztook ${helloTook}ns")

Slide 89

Slide 89 text

#07 Code Block Measurement var helloTook = measureTimeNanos {
 println("Hello, world!")
 }X helloTook += measureTimeNanos {
 println("Hello, world!")
 }X
 
 println("Saying 'hello' twiceZtook ${helloTook}ns") l

Slide 90

Slide 90 text

#08 Deprecation Levels

Slide 91

Slide 91 text

#08 Deprecation Levels fun join(sep: String, strings: List): String { 
 // ...
 }Z

Slide 92

Slide 92 text

#08 Deprecation Levels @Deprecated
 fun join(sep: String, strings: List): String { 
 // ...
 }Z

Slide 93

Slide 93 text

#08 Deprecation Levels @Deprecated
 fun join(sep: String, strings: List): String { 
 // ...
 }Z

Slide 94

Slide 94 text

#08 Deprecation Levels @Deprecated("Use strings.joinToString(sep).")
 fun join(sep: String, strings: List): String { 
 // ...
 }Z

Slide 95

Slide 95 text

#08 Deprecation Levels @Deprecated("Use strings.joinToString(sep).")X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z join(", ", listOf("me", "you"))

Slide 96

Slide 96 text

#08 Deprecation Levels import kotlin.DeprecationLevel.ERROR
 
 @Deprecated("Use strings.joinToString(sep).", level = ERROR)X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you"))

Slide 97

Slide 97 text

#08 Deprecation Levels import kotlin.DeprecationLevel.ERROR
 
 @Deprecated("Use strings.joinToString(sep).", level = ERROR)X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you"))

Slide 98

Slide 98 text

#08 Deprecation Levels import kotlin.DeprecationLevel.ERROR
 
 @Deprecated("Use strings.joinToString(sep).", level = ERROR)X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you")) Error:(10, 1) Kotlin: Using 'join(String, List): String' is an error. Use strings.joinToString(sep).

Slide 99

Slide 99 text

#08 Deprecation Levels import kotlin.DeprecationLevel.HIDDEN
 
 @Deprecated("Use strings.joinToString(sep).", level = HIDDEN)X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you")) ERROR ERROR Error:(10, 1) Kotlin: Using 'join(String, List): String' is an error. Use strings.joinToString(sep).

Slide 100

Slide 100 text

#08 Deprecation Levels import kotlin.DeprecationLevel.HIDDEN
 
 @Deprecated("Use strings.joinToString(sep).", level = HIDDEN)
 fun join(sep: String, strings: List): String { 
 // ...
 }
 
 join(", ", listOf("me", "you"))

Slide 101

Slide 101 text

#09 Deprecation Replacements

Slide 102

Slide 102 text

#09 Deprecation Replacements @Deprecated("Use strings.joinToString(sep).")X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z join(", ", listOf("me", "you"))

Slide 103

Slide 103 text

#09 Deprecation Replacements @Deprecated("Use strings.joinToString(sep).",
 replaceWith = ReplaceWith("strings.joinToString(sep)"))X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you"))

Slide 104

Slide 104 text

#09 Deprecation Replacements @Deprecated("Use strings.joinToString(sep).",
 replaceWith = ReplaceWith("strings.joinToString(sep)"))X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you"))

Slide 105

Slide 105 text

#09 Deprecation Replacements @Deprecated("Use strings.joinToString(sep).",
 replaceWith = ReplaceWith("strings.joinToString(sep)"))X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you"))

Slide 106

Slide 106 text

#09 Deprecation Replacements @Deprecated("Use strings.joinToString(sep).",
 replaceWith = ReplaceWith("strings.joinToString(sep)"))X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you"))

Slide 107

Slide 107 text

#09 Deprecation Replacements @Deprecated("Use strings.joinToString(sep).",
 replaceWith = ReplaceWith("strings.joinToString(sep)"))X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you"))

Slide 108

Slide 108 text

#09 Deprecation Replacements @Deprecated("Use strings.joinToString(sep).",
 replaceWith = ReplaceWith("strings.joinToString(sep)"))X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 listOf("me", "you").joinToString(", ")

Slide 109

Slide 109 text

#09 Deprecation Replacements @Deprecated("Use strings.joinToString(sep).",
 replaceWith = ReplaceWith("strings.joinToString(sep)"))X
 fun join(sep: String, strings: List): String { 
 // ...
 }Z 
 
 
 
 
 
 join(", ", listOf("me", "you"))

Slide 110

Slide 110 text

#09 Deprecation Replacements @Deprecated("Use Guava's Joiner.",
 replaceWith = ReplaceWith("Joiner.on(sep).join(strings)",
 imports = "com.google.common.base.Joiner"))X fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you")) strings.joinToString(sep) 
 .joinToString(

Slide 111

Slide 111 text

#09 Deprecation Replacements @Deprecated("Use Guava's Joiner.",
 replaceWith = ReplaceWith("Joiner.on(sep).join(strings)",
 imports = "com.google.common.base.Joiner"))X fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you"))X 
 
 
 
 Joiner.on(", ").join(listOf("me", "you"))

Slide 112

Slide 112 text

#09 Deprecation Replacements import com.google.common.base.Joiner
 @Deprecated("Use Guava's Joiner.",
 replaceWith = ReplaceWith("Joiner.on(sep).join(strings)",
 imports = "com.google.common.base.Joiner"))X fun join(sep: String, strings: List): String { 
 // ...
 }Z
 
 Joiner.on(", ").join(listOf("me", "you")) 
 
 
 
 
 
 join(", ", listOf("me", "you"))X

Slide 113

Slide 113 text

#10 Erasing Erasure

Slide 114

Slide 114 text

#10 Erasing Erasure class Foo : Callable, Callable {
 }

Slide 115

Slide 115 text

#10 Erasing Erasure class Foo : Callable, Callable {
 }

Slide 116

Slide 116 text

#10 Erasing Erasure fun sort(strings: List) {
 // ...
 }Y 
 fun sort(ints: List) {
 // ...
 }Z

Slide 117

Slide 117 text

#10 Erasing Erasure fun sort(strings: List) {
 // ...
 }Y 
 fun sort(ints: List) {
 // ...
 }Z

Slide 118

Slide 118 text

#10 Erasing Erasure fun sort(strings: List) {
 // ...
 }Y 
 fun sort(ints: List) {
 // ...
 }Z

Slide 119

Slide 119 text

#10 Erasing Erasure fun sortStrings(strings: List) {
 // ...
 }Y 
 fun sortInts(ints: List) {
 // ...
 }Z

Slide 120

Slide 120 text

#10 Erasing Erasure fun sort(strings: List) {
 // ...
 }Y 
 fun sort(ints: List) {
 // ...
 }Z

Slide 121

Slide 121 text

#10 Erasing Erasure @JvmName("sortStrings")
 fun sort(strings: List) {
 // ...
 }Y
 @JvmName("sortInts")
 fun sort(ints: List) {
 // ...
 }Z

Slide 122

Slide 122 text

#11 Dagger 2

Slide 123

Slide 123 text

#11 Dagger 2 • It works!

Slide 124

Slide 124 text

jakewharton jakewharton jakewharton twitter.com/ google.com/+ .com 10 Kotlin Tricks In 10(ish) Minutes