Slide 1

Slide 1 text

Kotlin, beyond the basics

Slide 2

Slide 2 text

segunfamisa segunfamisa.com

Slide 3

Slide 3 text

Intro

Slide 4

Slide 4 text

Imperative vs Functional Programming

Slide 5

Slide 5 text

Imperative vs Functional Programming Functions in Kotlin - lambdas, stdlib functions, etc

Slide 6

Slide 6 text

Imperative vs Functional Programming Functions in Kotlin - lambdas, stdlib functions, etc Java & Kotlin Interop

Slide 7

Slide 7 text

Imperative vs Functional programming

Slide 8

Slide 8 text

Functional == actions are composed into functions and usually reads as “what is done” Imperative == structured in steps of execution and usually reads as “how it’s done” Imperative == structured in steps of execution and usually reads as “how it’s done”

Slide 9

Slide 9 text

Functional == actions are composed into functions and usually reads as “what is done” Imperative == structured in steps of execution and usually reads as “how it’s done” Functional == actions are composed into functions and usually reads as “what is done” Imperative == structured in steps of execution and usually reads as “how it’s done”

Slide 10

Slide 10 text

// Java - print even numbers for (int i = start; i < end; i++) { if (i % 2 == 0) { System.out.println(i); } }

Slide 11

Slide 11 text

// Java - print even numbers for (int i = start; i < end; i++) { if (i % 2 == 0) { System.out.println(i); } } // Kotlin - print even numbers (start until end) .filter { it % 2 == 0 } .map { println(it) }

Slide 12

Slide 12 text

Imperative Functional

Slide 13

Slide 13 text

Imperative Functional Immutability isn’t encouraged at language level Encourages immutability

Slide 14

Slide 14 text

Imperative Functional Immutability isn’t encouraged at language level Encourages immutability Instances of classes, structures, objects are first class citizens Functions are first class citizens

Slide 15

Slide 15 text

Imperative Functional Immutability isn’t encouraged at language level Encourages immutability Instances of classes, structures, objects are first class citizens Functions are first class citizens Loops, method calls, conditionals Function calls

Slide 16

Slide 16 text

Imperative Functional Immutability isn’t encouraged at language level Encourages immutability Instances of classes, structures, objects are first class citizens Functions are first class citizens Loops, method calls, conditionals Function calls Side-effects allowed in functions Pure functions

Slide 17

Slide 17 text

functions in Kotlin

Slide 18

Slide 18 text

Functions are first class citizens

Slide 19

Slide 19 text

Functions are first class citizens They can: ● be stored in a variable - just like other types

Slide 20

Slide 20 text

Functions are first class citizens They can: ● be stored in a variable - just like other types ● take another function as parameter

Slide 21

Slide 21 text

Functions are first class citizens They can: ● be stored in a variable - just like other types ● take another function as parameter ● return a function

Slide 22

Slide 22 text

Functions are first class citizens They can: ● be stored in a variable - just like other types ● take another function as parameter ● return a function a.k.a higher order functions

Slide 23

Slide 23 text

Lambdas & higher order functions

Slide 24

Slide 24 text

Lambdas & higher order functions fun atLeastAndroidP(action: () -> Unit) { ... }

Slide 25

Slide 25 text

Lambdas & higher order functions fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } }

Slide 26

Slide 26 text

Lambdas & higher order functions // Usage: atLeastAndroidP { // do something on Android P } fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } }

Slide 27

Slide 27 text

Lambdas & higher order functions fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } } Lambda // Usage: atLeastAndroidP { // do something on Android P }

Slide 28

Slide 28 text

Lambdas & higher order functions fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } } Higher order function // Usage: atLeastAndroidP { // do something on Android P }

Slide 29

Slide 29 text

Lambdas & higher order functions // Usage: atLeastAndroidP { // do something on Android P } fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } }

Slide 30

Slide 30 text

Lambdas & higher order functions // Usage: atLeastAndroidP { // do something on Android P } fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } } Tip: Take a look at the generated code to understand what’s happening under the hood

Slide 31

Slide 31 text

Lambdas & higher order functions // Generated Java code public final void atLeastAndroidP(@NotNull Function0 action) { if (VERSION.SDK_INT > 28) { action.invoke(); } } fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } }

Slide 32

Slide 32 text

Lambdas & higher order functions // Generated Java code public final void atLeastAndroidP(@NotNull Function0 action) { if (VERSION.SDK_INT > 28) { action.invoke(); } } Every lambda is an object! Not great for performance fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } }

Slide 33

Slide 33 text

() -> Unit Function0 (Int) -> Boolean Function1 (Int, String) -> Boolean Function2 Every lambda corresponds to a FunctionN interface - where N is the number of params in the lambda

Slide 34

Slide 34 text

Lambdas & higher order functions // FunctionN interfaces used by Kotlin interface Function0 : Function interface Function1 : Function interface Function2 : Function ... interface Function22 : Function { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2...p22: P22): R }

Slide 35

Slide 35 text

Improving lambdas’ performance - the inline keyword // Kotlin fun atLeastAndroidP(action: () -> Unit) {...}

Slide 36

Slide 36 text

Improving lambdas’ performance - the inline keyword // Kotlin inline fun atLeastAndroidP(action: () -> Unit) {...}

Slide 37

Slide 37 text

Improving lambdas’ performance - the inline keyword // Kotlin inline fun atLeastAndroidP(action: () -> Unit) {...} // Usage: fun doSomethingOnP() { atLeastAndroidP { println("I'm on Android P") } }

Slide 38

Slide 38 text

Improving lambdas’ performance - the inline keyword // Kotlin inline fun atLeastAndroidP(action: () -> Unit) {...} // Usage: fun doSomethingOnP() { atLeastAndroidP { println("I'm on Android P") } } // Generated Java code public final void doSomethingOnP() { if (VERSION.SDK_INT > 28) { String var0 = "I'm on Android P"; System.out.println(var0); } }

Slide 39

Slide 39 text

Improving lambdas’ performance - the inline keyword // Kotlin inline fun atLeastAndroidP(action: () -> Unit) {...} // Usage: fun doSomethingOnP() { atLeastAndroidP { println("I'm on Android P") } } // Generated Java code public final void doSomethingOnP() { if (VERSION.SDK_INT > 28) { String var0 = "I'm on Android P"; System.out.println(var0); } } Method body is copied to the call site

Slide 40

Slide 40 text

Other good-to-know concepts when working with lambdas:

Slide 41

Slide 41 text

noinline keyword - used to mark lambdas in an inline function that we don’t want to inline Other good-to-know concepts when working with lambdas:

Slide 42

Slide 42 text

noinline keyword - used to mark lambdas in an inline function that we don’t want to inline Other good-to-know concepts when working with lambdas: inline fun atLeastAndroidP(action: () -> Unit, noinline fallback: () -> Unit) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { action() } else { fallback() } }

Slide 43

Slide 43 text

noinline keyword - used to mark other lambda params in an inline function that we don’t want to inline Other good-to-know concepts when working with lambdas: inline fun atLeastAndroidP(action: () -> Unit, noinline fallback: () -> Unit) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { action() } else { fallback() } } the `fallback` lambda is not inlined

Slide 44

Slide 44 text

non-local returns - typically non-local returns are not allowed within lambdas unless the function is inlined. Other good-to-know concepts when working with lambdas:

Slide 45

Slide 45 text

non-local returns - typically non-local returns are not allowed within lambdas unless the function is inlined. fun useNormalLambda() { normalLambda { ... return@normalLambda // works fine (local return) } } Other good-to-know concepts when working with lambdas:

Slide 46

Slide 46 text

non-local returns - typically non-local returns are not allowed within lambdas unless the function is inlined. fun useNormalLambda() { normalLambda { ... return@normalLambda // works fine (local return) return // compile error (non-local return) } } Other good-to-know concepts when working with lambdas:

Slide 47

Slide 47 text

non-local returns - typically non-local returns are not allowed within lambdas unless the function is inlined. Other good-to-know concepts when working with lambdas: fun useNormalLambda() { normalLambda { ... return@normalLambda // works fine (local return) return // compile error (non-local return } } fun useInlineLambda() { inlineLambda { return // works fine. Returns from useInlineLambda } }

Slide 48

Slide 48 text

crossinline keyword - used when the lambdas are not used directly in the inline function Other good-to-know concepts when working with lambdas:

Slide 49

Slide 49 text

crossinline keyword - used when the lambdas are not used directly in the inline function Other good-to-know concepts when working with lambdas: inline fun View.waitForLayout(crossinline action: () -> Unit) = with(viewTreeObserver) { addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { [email protected](this) action() } }) }

Slide 50

Slide 50 text

crossinline keyword - used when the lambdas are not used directly in the inline function Other good-to-know concepts when working with lambdas: inline fun View.waitForLayout(crossinline action: () -> Unit) = with(viewTreeObserver) { addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { [email protected](this) action() } }) } Non-local returns are not allowed within the lambda

Slide 51

Slide 51 text

Standard library functions let, run, apply, also

Slide 52

Slide 52 text

Standard library functions Some of these functions are also referred to as Scoping functions

Slide 53

Slide 53 text

let - Standard.kt public inline fun T.let(block: (T) -> R): R = block(this)

Slide 54

Slide 54 text

let - Standard.kt public inline fun T.let(block: (T) -> R): R = block(this) Lambda function

Slide 55

Slide 55 text

let - Standard.kt public inline fun T.let(block: (T) -> R): R = block(this) Receiver

Slide 56

Slide 56 text

let - Standard.kt public inline fun T.let(block: (T) -> R): R = block(this) // Sample usage client?.email ?.let { mailer.sendMessage(it, message) }

Slide 57

Slide 57 text

let - Standard.kt // Sample usage client?.email ?.let { mailer.sendMessage(it, message) } public inline fun T.let(block: (T) -> R): R = block(this)

Slide 58

Slide 58 text

let - Standard.kt // Sample usage client?.email ?.let { mailer.sendMessage(it, message) } // Or client?.email ?.let { email -> mailer.sendMessage(email, message) } public inline fun T.let(block: (T) -> R): R = block(this)

Slide 59

Slide 59 text

run - Standard.kt public inline fun T.run(block: T.() -> R): R = block() Runs the block of code and returns the last line in the lambda

Slide 60

Slide 60 text

run - Standard.kt public inline fun T.run(block: T.() -> R): R = block() Receiver

Slide 61

Slide 61 text

run - Standard.kt public inline fun T.run(block: T.() -> R): R = block() Function literal with receiver

Slide 62

Slide 62 text

run - Standard.kt public inline fun T.run(block: T.() -> R): R = block() // Sample usage fun performTransformation(input: String) : String {...} val transformedName = name.run { println("Transforming name...") val transformedString = performTransformation(this) transformedString }

Slide 63

Slide 63 text

run - Standard.kt public inline fun T.run(block: T.() -> R): R = block() // Sample usage fun performTransformation(input: String) : String {...} val transformedName = name.run { println("Transforming name...") val transformedString = performTransformation(this) transformedString }

Slide 64

Slide 64 text

run - Standard.kt public inline fun T.run(block: T.() -> R): R = block() // Sample usage fun performTransformation(input: String) : String {...} val transformedName = name.run { println("Transforming name...") val transformedString = performTransformation(this) transformedString }

Slide 65

Slide 65 text

run - Standard.kt public inline fun T.run(block: T.() -> R): R = block() // Sample usage fun performTransformation(input: String) : String {...} val transformedName = name.run { println("Transforming name...") val transformedString = performTransformation(this) transformedString } Receiver is accessed as “this”, and exposes the inner members of the receiver class

Slide 66

Slide 66 text

run - Standard.kt public inline fun T.run(block: T.() -> R): R = block() // Sample usage fun performTransformation(input: String) : String {...} val transformedName = name.run { println("Transforming name...") val transformedString = performTransformation(this) transformedString } transformedString is returned from the lambda

Slide 67

Slide 67 text

also - Standard.kt inline fun T.also(block: (T) -> Unit): T { block(this); return this }

Slide 68

Slide 68 text

also - Standard.kt inline fun T.also(block: (T) -> Unit): T { block(this); return this } // Sample usage val dev = Developer().also { it.name = "Segun" it.lovesCatVideos = true it.stack = "Android" }

Slide 69

Slide 69 text

also - Standard.kt inline fun T.also(block: (T) -> Unit): T { block(this); return this } The receiver is accessed as “it” // Sample usage val dev = Developer().also { it.name = "Segun" it.lovesCatVideos = true it.stack = "Android" }

Slide 70

Slide 70 text

also - Standard.kt inline fun T.also(block: (T) -> Unit): T { block(this); return this } // Sample usage val dev = Developer().also { it.name = "Segun" it.lovesCatVideos = true it.stack = "Android" } // OR val dev = Developer().also { developer -> developer.name = "Segun" developer.lovesCatVideos = true developer.stack = "Android" }

Slide 71

Slide 71 text

apply - Standard.kt inline fun T.apply(block: T.() -> Unit): T { block(); return this }

Slide 72

Slide 72 text

apply - Standard.kt inline fun T.apply(block: T.() -> Unit): T { block(); return this } // Sample usage val dev = Developer().apply { this.name = "Segun" this.lovesCatVideos = true this.stack = "Android" }

Slide 73

Slide 73 text

apply - Standard.kt inline fun T.apply(block: T.() -> Unit): T { block(); return this } // Sample usage val dev = Developer().apply { this.name = "Segun" this.lovesCatVideos = true this.stack = "Android" } Exposes the receiver as “this”

Slide 74

Slide 74 text

Things to consider

Slide 75

Slide 75 text

Things to consider ● Avoid overusing these scoping functions - readability can degrade quickly

Slide 76

Slide 76 text

Things to consider ● Avoid overusing these scoping functions - readability can degrade quickly ● Consider renaming it to something better when possible

Slide 77

Slide 77 text

Things to consider ● Avoid overusing these scoping functions - readability can degrade quickly ● Consider renaming it to something better when possible ● More stdlib functions ○ takeIf, takeUnless, with, etc

Slide 78

Slide 78 text

stdlib functions in action

Slide 79

Slide 79 text

// Java code public void sendMessageToClient( @Nullable Client client, @Nullable String message, @NotNull Mailer mailer ) { if (client == null || message == null) return; PersonalInfo personalInfo = client.getPersonalInfo(); if (personalInfo == null) return; String email = personalInfo.getEmail(); if (email == null) return; mailer.sendMessage(email, message); } stdlib functions in action

Slide 80

Slide 80 text

// Java code public void sendMessageToClient( @Nullable Client client, @Nullable String message, @NotNull Mailer mailer ) { if (client == null || message == null) return; PersonalInfo personalInfo = client.getPersonalInfo(); if (personalInfo == null) return; String email = personalInfo.getEmail(); if (email == null) return; mailer.sendMessage(email, message); } // Kotlin equivalent fun sendMessageToClient( client: Client?, message: String?, mailer: Mailer ) { client?.takeIf { message != null } ?.personalInfo ?.email ?.let { email -> mailer.sendMessage(email, message!!) } } stdlib functions in action

Slide 81

Slide 81 text

// Java code public void sendMessageToClient( @Nullable Client client, @Nullable String message, @NotNull Mailer mailer ) { if (client == null || message == null) return; PersonalInfo personalInfo = client.getPersonalInfo(); if (personalInfo == null) return; String email = personalInfo.getEmail(); if (email == null) return; mailer.sendMessage(email, message); } // Kotlin equivalent fun sendMessageToClient( client: Client?, message: String?, mailer: Mailer ) { client?.takeIf { message != null } ?.personalInfo ?.email ?.let { email -> mailer.sendMessage(email, message!!) } } stdlib functions in action

Slide 82

Slide 82 text

// Java code public void sendMessageToClient( @Nullable Client client, @Nullable String message, @NotNull Mailer mailer ) { if (client == null || message == null) return; PersonalInfo personalInfo = client.getPersonalInfo(); if (personalInfo == null) return; String email = personalInfo.getEmail(); if (email == null) return; mailer.sendMessage(email, message); } // Kotlin equivalent fun sendMessageToClient( client: Client?, message: String?, mailer: Mailer ) { client?.takeIf { message != null } ?.personalInfo ?.email ?.let { email -> mailer.sendMessage(email, message!!) } } stdlib functions in action

Slide 83

Slide 83 text

// Java code public void sendMessageToClient( @Nullable Client client, @Nullable String message, @NotNull Mailer mailer ) { if (client == null || message == null) return; PersonalInfo personalInfo = client.getPersonalInfo(); if (personalInfo == null) return; String email = personalInfo.getEmail(); if (email == null) return; mailer.sendMessage(email, message); } // Kotlin equivalent fun sendMessageToClient( client: Client?, message: String?, mailer: Mailer ) { client?.takeIf { message != null } ?.personalInfo ?.email ?.let { email -> mailer.sendMessage(email, message!!) } } stdlib functions in action Functional, readable, concise

Slide 84

Slide 84 text

Java & Kotlin Interoperability ...a tale of 2 islands

Slide 85

Slide 85 text

Java & Kotlin Interoperability Important because: ● Android APIs are written in Java

Slide 86

Slide 86 text

Java & Kotlin Interoperability Important because: ● Android APIs are written in Java ● Kotlin & Java may be mixed in the same codebase

Slide 87

Slide 87 text

- nullability Java & Kotlin Interoperability

Slide 88

Slide 88 text

String! String? What do these mean when you think about nullability & types? String Pop

Slide 89

Slide 89 text

String! String? String Non-nullable type Nullable type Platform type Kotlin compiler has no idea whether it’s nullable or not

Slide 90

Slide 90 text

types are very important when considering interoperability between Java & Kotlin

Slide 91

Slide 91 text

String String? String or

Slide 92

Slide 92 text

// Calling Java from Kotlin // Compiles fine. Safe in runtime val nameLength = myObject.name.length // Java @NotNull public String getName() { return "Segun"; } ...

Slide 93

Slide 93 text

// Calling Java from Kotlin // Compiler error. Need safe access val nameLength = myObject.name.length // Java @Nullable public String getName() { return null; } ...

Slide 94

Slide 94 text

// Calling Java from Kotlin // Compiler error. Need safe access val nameLength = myObject.name.length // Compiles fine. Safe in runtime val nameLength = myObject.name?.length // Java @Nullable public String getName() { return null; } ...

Slide 95

Slide 95 text

// Calling Java from Kotlin // Compiles fine. NPE in runtime val nameLength = myObject.name.length // Java public String getName() { return null; } ...

Slide 96

Slide 96 text

// Java public String getName() { return null; } ... // Calling Java from Kotlin // Compiles fine. NPE in runtime val nameLength = myObject.name.length // Compiles fine. Safe in runtime val nameLength = myObject.name?.length

Slide 97

Slide 97 text

@Nullable String getName() {..} Kotlin compiler treats as nullable “?” @NotNull String getName() {..} Kotlin compiler treats as non-nullable String getName() {..} Kotlin compiler has no clue. Treats as platform type

Slide 98

Slide 98 text

- calling Kotlin from Java Java & Kotlin Interoperability

Slide 99

Slide 99 text

Kotlin package-level functions

Slide 100

Slide 100 text

Kotlin package-level functions Functions can be defined in a file directly without being in any class or object. // InteropDemo.kt fun getName() = "Segun"

Slide 101

Slide 101 text

Kotlin package-level functions Functions can be defined in a file directly without being in any class or object. // InteropDemo.kt fun getName() = "Segun" // Calling from Java InteropDemoKt.getName();

Slide 102

Slide 102 text

Kotlin package-level functions @JvmName annotation helps to tell Kotlin compiler what the generated Java class name should be when consumed from Java

Slide 103

Slide 103 text

Kotlin package-level functions // InteropDemo.kt @file:JvmName("InteropDemo") fun getName() = "Segun" @JvmName annotation helps to tell Kotlin compiler what the generated Java class name should be when consumed from Java

Slide 104

Slide 104 text

Kotlin package-level functions // InteropDemo.kt @file:JvmName("InteropDemo") fun getName() = "Segun" // Calling from Java InteropDemo.getName(); @JvmName annotation helps to tell Kotlin compiler what the generated Java class name should be when consumed from Java

Slide 105

Slide 105 text

@JvmName The annotation can also be applied to functions

Slide 106

Slide 106 text

@JvmName // Kotlin code @JvmName("getInteropName") fun getName() = "Segun" The annotation can also be applied to functions

Slide 107

Slide 107 text

@JvmName // Kotlin code @JvmName("getInteropName") fun getName() = "Segun" // Consumed from Java demo.getInteropName(); The annotation can also be applied to functions

Slide 108

Slide 108 text

@JvmName The annotation can also be applied to functions // Kotlin code @JvmName("getInteropName") fun getName() = "Segun" // Consumed from Java demo.getInteropName(); // Consumed from Kotlin demo.getName()

Slide 109

Slide 109 text

@JvmStatic Kotlin does not have static methods. Instead, it has objects, companion objects

Slide 110

Slide 110 text

@JvmStatic // Kotlin Object object StringUtils { fun upperCase(text: String) = text.toUpperCase() }

Slide 111

Slide 111 text

@JvmStatic // Kotlin Object object StringUtils { fun upperCase(text: String) = text.toUpperCase() } // Calling from Java String upperCaseName = StringUtils.INSTANCE.upperCase("Segun");

Slide 112

Slide 112 text

@JvmStatic // Kotlin Object object StringUtils { + @JvmStatic fun upperCase(text: String) = text.toUpperCase() } // Calling from Java String upperCaseName = StringUtils.INSTANCE.upperCase("Segun");

Slide 113

Slide 113 text

@JvmStatic // Kotlin Object object StringUtils { + @JvmStatic fun upperCase(text: String) = text.toUpperCase() } // Calling from Java String upperCaseName = StringUtils.INSTANCE.upperCase("Segun"); String upperCaseName = StringUtils.upperCase("Segun");

Slide 114

Slide 114 text

@JvmStatic - Static providers in Dagger Specially useful when working with Dagger static Providers on Android

Slide 115

Slide 115 text

@Module abstract class RepositoryModule { @Binds abstract fun bindRepo(repository: Repository): IRepository companion object { // static provider @Provides fun provideApiService: ApiService = ... } } @JvmStatic - Static providers in Dagger

Slide 116

Slide 116 text

@Module abstract class RepositoryModule { @Binds abstract fun bindRepo(repository: Repository): IRepository companion object { // static provider @Provides fun provideApiService: ApiService = ... } } Won’t compile. Dagger error. Why? @JvmStatic - Static providers in Dagger

Slide 117

Slide 117 text

@JvmStatic - Static providers in Dagger // Generated Java class @Module public abstract class RepositoryModule { ... @Binds @NotNull public abstract IRepository bindRepo(@NotNull Repository var1); public static final class Companion { @Provides @NotNull public final ApiService providesApiService() {...} } }

Slide 118

Slide 118 text

@JvmStatic - Static providers in Dagger // Generated Java class @Module public abstract class RepositoryModule { ... @Binds @NotNull public abstract IRepository bindRepo(@NotNull Repository var1); public static final class Companion { @Provides @NotNull public final ApiService providesApiService() {...} } } No @Module

Slide 119

Slide 119 text

@JvmStatic - Static providers in Dagger // Generated Java class @Module public abstract class RepositoryModule { ... @Binds @NotNull public abstract IRepository bindRepo(@NotNull Repository var1); public static final class Companion { @Provides @NotNull public final ApiService providesApiService() {...} } } No @Module @Provides method is generated as a member of the Companion class

Slide 120

Slide 120 text

@JvmStatic - Static providers in Dagger // Generated Java class @Module public abstract class RepositoryModule { ... @Binds @NotNull public abstract IRepository bindRepo(@NotNull Repository var1); public static final class Companion { @Provides @NotNull public final ApiService providesApiService() {...} } } No @Module @Provides method is generated as a member of the Companion class Dagger is unable to provide this dependency

Slide 121

Slide 121 text

@JvmStatic - Static providers in Dagger @Module abstract class RepositoryModule { @Binds abstract fun bindRepo(repository: Repository): IRepository + @Module companion object { // static provider @Provides + @JvmStatic fun provideApiService: ApiService = ... } } Fixed by adding @Module and @JvmStatic annotations

Slide 122

Slide 122 text

@JvmStatic - Static providers in Dagger Fixed by adding @Module and @JvmStatic annotations // Generated Java class with fixes @Module public abstract class RepositoryModule { @Binds public abstract IRepository bindRepos(@NotNull Repository var1); @Provides @JvmStatic public static final ApiService providesApiService() {...} @Module public static final class Companion { @Provides @JvmStatic public final ApiService providesApiService() {...} ... } } Kotlin compiler generates a static method within the RepositoryModule class

Slide 123

Slide 123 text

@JvmStatic - Static providers in Dagger Fixed by adding @Module and @JvmStatic annotations // Generated Java class with fixes @Module public abstract class RepositoryModule { @Binds public abstract IRepository bindRepos(@NotNull Repository var1); @Provides @JvmStatic public static final ApiService providesApiService() {...} @Module public static final class Companion { @Provides @JvmStatic public final ApiService providesApiService() {...} ... } } Dagger will see this module, but generated code will not be used. RepositoryModule.Companion module isn’t registered

Slide 124

Slide 124 text

@JvmOverloads

Slide 125

Slide 125 text

@JvmOverloads // Kotlin class with default values class Point(val x: Int = 0, val y: Int = 0)

Slide 126

Slide 126 text

@JvmOverloads // Kotlin class with default values class Point(val x: Int = 0, val y: Int = 0) // Calling from Java Point p1 = new Point(); Point p2 = new Point(1, 3);

Slide 127

Slide 127 text

@JvmOverloads // Kotlin class with default values class Point(val x: Int = 0, val y: Int = 0) // Calling from Java Point p1 = new Point(); Point p2 = new Point(1, 3); Specify none or all params

Slide 128

Slide 128 text

@JvmOverloads // Kotlin class with default values class Point @JvmOverloads constructor(val x: Int = 0, val y: Int = 0)

Slide 129

Slide 129 text

@JvmOverloads // Kotlin class with default values class Point @JvmOverloads constructor(val x: Int = 0, val y: Int = 0) // Generated Java code public final class Point { // Overloaded constructors public Point() {...} public Point(int x) {...} public Point(int x, int y) {...} }

Slide 130

Slide 130 text

@JvmOverloads // Calling from Java Point p1 = new Point(); Point p2 = new Point(1); Point p3 = new Point(1, 3); // Kotlin class with default values class Point @JvmOverloads constructor(val x: Int = 0, val y: Int = 0) // Generated Java code public final class Point { // Overloaded constructors public Point() {...} public Point(int x) {...} public Point(int x, int y) {...} }

Slide 131

Slide 131 text

@JvmOverloads Also works on other functions that are not constructors

Slide 132

Slide 132 text

@Jvm* annotations There are more: @JvmField @JvmSuppressWildcards @JvmMultifileClass... etc

Slide 133

Slide 133 text

Resources KotlinConf videos #Kotlin on twitter Kotlinweekly.net kotlinlang.org

Slide 134

Slide 134 text

Thank you segunfamisa segunfamisa.com