Slide 1

Slide 1 text

Copenhagen Denmark EFFECTIVE SWIFT- KOTLIN INTEROPERABILITY JOHN RODRIGUEZ @jrodbx

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

@objc

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

include ':app' settings.gradle settings.gradle

Slide 10

Slide 10 text

include ':app' include ':SharedCode' settings.gradle

Slide 11

Slide 11 text

plugins { kotlin("multiplatform") } kotlin { … iOSTarget("ios") { binaries { framework { baseName = "ESKIOFramework" } } } jvm("android") sourceSets["commonMain"].dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-common") SharedCode/build.gradle.kts

Slide 12

Slide 12 text

} } jvm("android") sourceSets["commonMain"].dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-common") } sourceSets["androidMain"].dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib") } } val packForXcode by tasks.creating(Sync::class) { val targetDir = File(buildDir, "xcode-frameworks") /// selecting the right configuration for the iOS /// framework depending on the environment /// variables set by Xcode build val mode = System.getenv("CONFIGURATION") ?: "DEBUG" val framework = kotlin.targets .getByName("ios") SharedCode/build.gradle.kts

Slide 13

Slide 13 text

implementation("org.jetbrains.kotlin:kotlin-stdlib") } } val packForXcode by tasks.creating(Sync::class) { val targetDir = File(buildDir, "xcode-frameworks") … val framework = kotlin.targets .getByName("ios") .binaries.getFramework(…) dependsOn(framework.linkTask) from({ framework.outputDirectory }) into(targetDir) … } tasks.getByName("build").dependsOn(packForXcode) SharedCode/build.gradle.kts

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

http://bit.ly/2RvF72h

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

ipa apk

Slide 26

Slide 26 text

jar framework aar actual/expect expect/actual SharedCode ipa apk

Slide 27

Slide 27 text

apk ipa jar framework aar aar jar Klib actual/expect expect/actual SharedCode actual/expect expect/actual Gradle dependencies

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

object Object class Clazz interface Interface { fun member() {} } SharedCode/src/commonMain/kotlin/demoCommon.kt

Slide 30

Slide 30 text

object Object class Clazz interface Interface { fun member() {} } let obj1 = Object() print(address(o: obj1)) let obj2 = Object() print(address(o: obj2)) let class1 = Clazz() print(address(o: class1)) let class2 = Clazz() print(address(o: class2))

Slide 31

Slide 31 text

object Object class Clazz interface Interface { fun member() {} } let obj1 = Object() print(address(o: obj1)) let obj2 = Object() print(address(o: obj2)) let class1 = Clazz() print(address(o: class1)) let class2 = Clazz() print(address(o: class2)) 105553140519616 105553140519616 105553140519264 105553140519072

Slide 32

Slide 32 text

@interface KotlinBase : NSObject - (instancetype)init __attribute__((unavailable)); + (instancetype)new __attribute__((unavailable)); + (void)initialize __attribute__((objc_requires_super)); @end; __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("Object"))) @interface ESKIOFObject : KotlinBase + (instancetype)object __attribute__((swift_name("init()"))); @end; __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("Clazz"))) @interface ESKIOFClazz : KotlinBase - (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)); @end; KotliniOS/Frameworks/ESKIOFramework.framework/Headers/ESKIOFramework.h

Slide 33

Slide 33 text

@interface KotlinBase : NSObject - (instancetype)init __attribute__((unavailable)); + (instancetype)new __attribute__((unavailable)); + (void)initialize __attribute__((objc_requires_super)); @end; __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("Object"))) @interface ESKIOFObject : KotlinBase + (instancetype)object __attribute__((swift_name("init()"))); @end; __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("Clazz"))) @interface ESKIOFClazz : KotlinBase - (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)); @end; KotliniOS/Frameworks/ESKIOFramework.framework/Headers/ESKIOFramework.h

Slide 34

Slide 34 text

@interface KotlinBase : NSObject - (instancetype)init __attribute__((unavailable)); + (instancetype)new __attribute__((unavailable)); + (void)initialize __attribute__((objc_requires_super)); @end; __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("Object"))) @interface ESKIOFObject : KotlinBase + (instancetype)object __attribute__((swift_name("init()"))); @end; __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("Clazz"))) @interface ESKIOFClazz : KotlinBase - (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)); @end; KotliniOS/Frameworks/ESKIOFramework.framework/Headers/ESKIOFramework.h

Slide 35

Slide 35 text

@interface KotlinBase : NSObject - (instancetype)init __attribute__((unavailable)); + (instancetype)new __attribute__((unavailable)); + (void)initialize __attribute__((objc_requires_super)); @end; __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("Object"))) @interface ESKIOFObject : KotlinBase + (instancetype)object __attribute__((swift_name("init()"))); @end; __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("Clazz"))) @interface ESKIOFClazz : KotlinBase - (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)); @end; KotliniOS/Frameworks/ESKIOFramework.framework/Headers/ESKIOFramework.h

Slide 36

Slide 36 text

fun plusplus(value: Int): Int { return value + 1 } SharedCode/src/commonMain/kotlin/demoCommon.kt

Slide 37

Slide 37 text

fun plusplus(value: Int): Int { return value + 1 } let value = 5 DemoCommonKt.plusplus(value: value)

Slide 38

Slide 38 text

let value = 5 DemoCommonKt.plusplus(value: value) fun plusplus(value: Int): Int { return value + 1 } Cannot convert value … 'Int' to … 'Int32' _

Slide 39

Slide 39 text

__attribute__((objc_subclassing_restricted)) __attribute__((swift_name("DemoCommonKt"))) @interface ESKIOFDemoCommonKt : KotlinBase … + (int32_t)plusplusValue:(int32_t)value __attribute__((swift_name("plusplus(value:)"))); … @end; KotliniOS/Frameworks/ESKIOFramework.framework/Headers/ESKIOFramework.h

Slide 40

Slide 40 text

__attribute__((objc_subclassing_restricted)) __attribute__((swift_name("DemoCommonKt"))) @interface ESKIOFDemoCommonKt : KotlinBase … + (int32_t)plusplusValue:(int32_t)value __attribute__((swift_name("plusplus(value:)"))); … @end; KotliniOS/Frameworks/ESKIOFramework.framework/Headers/ESKIOFramework.h

Slide 41

Slide 41 text

let value = 5 DemoCommonKt.plusplus(value: value) fun plusplus(value: Int): Int { return value + 1 } Cannot convert value … 'Int' to … 'Int32' _

Slide 42

Slide 42 text

let value = 5 as Int32 DemoCommonKt.plusplus(value: value) fun plusplus(value: Int): Int { return value + 1 } Cannot convert value … 'Int' to … 'Int32' _

Slide 43

Slide 43 text

let value = 5 as Int32 DemoCommonKt.plusplus(value: value) fun plusplus(value: Int): Int { return value + 1 } Cannot convert value … 'Int' to … 'Int32' _

Slide 44

Slide 44 text

fun plusplus(value: Int): Intx{ return valuex+x1 } let value = 5 as Int32 DemoCommonKt.plusplus(value: value)

Slide 45

Slide 45 text

fun plusplus(value: Int) = valuex+x1 fun plusplus(value: Long) = value + 1 fun plusplus(value: Double) = value + 1 fun plusplus(value: Float) = value + 1 let value = 5 as Int32 DemoCommonKt.plusplus(value: value)

Slide 46

Slide 46 text

fun plusplus(value: Int) = valuex+x1 fun plusplus(value: Long) = value + 1 fun plusplus(value: Double) = value + 1 fun plusplus(value: Float) = value + 1 let iValue = 5 as Int32 let lValue = 5 as Int64 let dValue = 5.0 let fValue: Float = 5.0 DemoCommonKt.plusplus(value__: iValue) DemoCommonKt.plusplus(value___: lValue) DemoCommonKt.plusplus(value: dValue) DemoCommonKt.plusplus(value_: fValue)

Slide 47

Slide 47 text

__attribute__((objc_subclassing_restricted)) __attribute__((swift_name("DemoCommonKt"))) @interface ESKIOFDemoCommonKt : KotlinBase … + (double)plusplusValue:(double)value __attribute__((swift_name("plusplus(value:)"))); + (float)plusplusValue_:(float)value __attribute__((swift_name("plusplus(value_:)"))); + (int32_t)plusplusValue__:(int32_t)value __attribute__((swift_name("plusplus(value__:)"))); + (int64_t)plusplusValue___:(int64_t)value __attribute__((swift_name("plusplus(value___:)"))); … @end; KotliniOS/Frameworks/ESKIOFramework.framework/Headers/ESKIOFramework.h

Slide 48

Slide 48 text

fun plusplus(value: Int) = valuex+x1 fun plusplus(value: Long) = value + 1 fun plusplus(value: Double) = value + 1 fun plusplus(value: Float) = value + 1 let iValue = 5 as Int32 let lValue = 5 as Int64 let dValue = 5.0 let fValue: Float = 5.0 DemoCommonKt.plusplus(value__: iValue) DemoCommonKt.plusplus(value___: lValue) DemoCommonKt.plusplus(value: dValue) DemoCommonKt.plusplus(value_: fValue)

Slide 49

Slide 49 text

fun plusplus(intValue: Int) = intValue +x1 fun plusplus(longValue: Long) = longValue + 1 fun plusplus(doubleValue: Double) = doubleValue + 1 fun plusplus(floatValue: Float) = floatValue + 1 let iValue = 5 as Int32 let lValue = 5 as Int64 let dValue = 5.0 let fValue: Float = 5.0 DemoCommonKt.plusplus(intValue: iValue) DemoCommonKt.plusplus(longValue: lValue) DemoCommonKt.plusplus(doubleValue: dValue) DemoCommonKt.plusplus(floatValue: fValue)

Slide 50

Slide 50 text

Compromises

Slide 51

Slide 51 text

Lack of Common Library Support*

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

Okio OkHttp Moshi Wire IO HTTP Client serialization

Slide 54

Slide 54 text

Okio OkHttp IO HTTP Client serialization Moshi? Wire

Slide 55

Slide 55 text

Okio OkHttp Moshi? Wire IO HTTP Client serialization DB SqlDelight

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

Avoid UI Layer

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

Language Features

Slide 61

Slide 61 text

enum class City { NEW_YORK, CHICAGO, NAPLES }

Slide 62

Slide 62 text

__attribute__((swift_name("City"))) @interface ESKIOFCity : ESKIOFKotlinEnum //… @property (class, readonly) ESKIOFCity *theNewYork __attribute__((swift_name("theNewYork"))); @property (class, readonly) ESKIOFCity *chicago __attribute__((swift_name("chicago"))); @property (class, readonly) ESKIOFCity *naples __attribute__((swift_name("naples"))); - (instancetype)initWithName:(NSString *)name ordinal:(int32_t)ordinal __attribute__((swift_name("init(name:ordinal:)"))); - (int32_t)compareToOther:(ESKIOFCity *)other __attribute__((swift_name("compareTo(other:)"))); @end;

Slide 63

Slide 63 text

__attribute__((swift_name("City"))) @interface ESKIOFCity : ESKIOFKotlinEnum //… @property (class, readonly) ESKIOFCity *theNewYork __attribute__((swift_name("theNewYork"))); @property (class, readonly) ESKIOFCity *chicago __attribute__((swift_name("chicago"))); @property (class, readonly) ESKIOFCity *naples __attribute__((swift_name("naples"))); - (instancetype)initWithName:(NSString *)name ordinal:(int32_t)ordinal __attribute__((swift_name("init(name:ordinal:)"))); - (int32_t)compareToOther:(ESKIOFCity *)other __attribute__((swift_name("compareTo(other:)"))); @end;

Slide 64

Slide 64 text

enum class City { NEW_YORK, CHICAGO, NAPLES }

Slide 65

Slide 65 text

enum class City { NEW_YORK, CHICAGO, NAPLES } let city = City.chicago switch city { case .chicago: print("Chicago!") case .naples: print("Naples!") case .theNewYork: print("New York!") }

Slide 66

Slide 66 text

enum class City { NEW_YORK, CHICAGO, NAPLES } let city = City.chicago switch city { case .chicago: print("Chicago!") case .naples: print("Naples!") case .theNewYork: print("New York!") } Switch must be exhaustive. _

Slide 67

Slide 67 text

__attribute__((swift_name("City"))) @interface ESKIOFCity : ESKIOFKotlinEnum //… @property (class, readonly) ESKIOFCity *theNewYork __attribute__((swift_name("theNewYork"))); @property (class, readonly) ESKIOFCity *chicago __attribute__((swift_name("chicago"))); @property (class, readonly) ESKIOFCity *naples __attribute__((swift_name("naples"))); - (instancetype)initWithName:(NSString *)name ordinal:(int32_t)ordinal __attribute__((swift_name("init(name:ordinal:)"))); - (int32_t)compareToOther:(ESKIOFCity *)other __attribute__((swift_name("compareTo(other:)"))); @end;

Slide 68

Slide 68 text

__attribute__((swift_name("City"))) @interface ESKIOFCity : ESKIOFKotlinEnum //… @property (class, readonly) ESKIOFCity *theNewYork __attribute__((swift_name("theNewYork"))); @property (class, readonly) ESKIOFCity *chicago __attribute__((swift_name("chicago"))); @property (class, readonly) ESKIOFCity *naples __attribute__((swift_name("naples"))); - (instancetype)initWithName:(NSString *)name ordinal:(int32_t)ordinal __attribute__((swift_name("init(name:ordinal:)"))); - (int32_t)compareToOther:(ESKIOFCity *)other __attribute__((swift_name("compareTo(other:)"))); @end;

Slide 69

Slide 69 text

__attribute__((swift_name("KotlinEnum"))) @interface ESKIOFKotlinEnum : KotlinBase - (instancetype)initWithName:(NSString *)name ordinal:(int32_t)ordinal __attribute__((swift_name("init(name:ordinal:)"))) __attribute__((objc_designated_initializer)); - (int32_t)compareToOther:(ESKIOFKotlinEnum *)other __attribute__((swift_name("compareTo(other:)"))); - (BOOL)isEqual:(id _Nullable)other __attribute__((swift_name("isEqual(_:)"))); - (NSUInteger)hash __attribute__((swift_name("hash()"))); - (NSString *)description __attribute__((swift_name("description()"))); @property (readonly) NSString *name __attribute__((swift_name("name"))); @property (readonly) int32_t ordinal __attribute__((swift_name("ordinal"))); @end;

Slide 70

Slide 70 text

__attribute__((swift_name("KotlinEnum"))) @interface ESKIOFKotlinEnum : KotlinBase - (instancetype)initWithName:(NSString *)name ordinal:(int32_t)ordinal __attribute__((swift_name("init(name:ordinal:)"))) __attribute__((objc_designated_initializer)); - (int32_t)compareToOther:(ESKIOFKotlinEnum *)other __attribute__((swift_name("compareTo(other:)"))); - (BOOL)isEqual:(id _Nullable)other __attribute__((swift_name("isEqual(_:)"))); - (NSUInteger)hash __attribute__((swift_name("hash()"))); - (NSString *)description __attribute__((swift_name("description()"))); @property (readonly) NSString *name __attribute__((swift_name("name"))); @property (readonly) int32_t ordinal __attribute__((swift_name("ordinal"))); @end;

Slide 71

Slide 71 text

enum class City { NEW_YORK, CHICAGO, NAPLES } let city = City.chicago switch city { case .chicago: print("Chicago!") case .naples: print("Naples!") case .theNewYork: print("New York!") } Switch must be exhaustive. _

Slide 72

Slide 72 text

enum class City { NEW_YORK, CHICAGO, NAPLES } let city = City.chicago switch city { case .chicago: print("Chicago!") case .naples: print("Naples!") case .theNewYork: print("New York!") default: fatalError("This can't be reached") }

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

enum City: RawRepresentable {a … }b

Slide 75

Slide 75 text

enum City: RawRepresentable {a case chicago case newyork case naples init(rawValue: ESKIOFramework.City) { switch (rawValue){ case .theNewYork: self = .newyork case .chicago: self = .chicago case .naples: self = .naples default: fatalError("This can't be reached") } } var rawValue: ESKIOFramework.City { switch(self){ case .newyork: return .theNewYork case .chicago: return .chicago case .naples: return .naples } } }b

Slide 76

Slide 76 text

enum City: RawRepresentable {a case chicago case newyork case naples init(rawValue: ESKIOFramework.City) { switch (rawValue){ case .theNewYork: self = .newyork case .chicago: self = .chicago case .naples: self = .naples default: fatalError("This can't be reached") } } var rawValue: ESKIOFramework.City { switch(self){ case .newyork: return .theNewYork case .chicago: return .chicago case .naples: return .naples } } }b

Slide 77

Slide 77 text

enum City: RawRepresentable {a case chicago case newyork case naples case unknown init(rawValue: ESKIOFramework.City) { switch (rawValue){ case .theNewYork: self = .newyork case .chicago: self = .chicago case .naples: self = .naples default: self = .unknown } } var rawValue: ESKIOFramework.City { switch(self){ case .newyork: return .theNewYork case .chicago: return .chicago case .naples: return .naples case .unknown: fatalError("This should never happen!") } }

Slide 78

Slide 78 text

enum class City { NEW_YORK, CHICAGO, NAPLES } let city = City.chicago switch city { case .chicago: print("Chicago!") case .naples: print("Naples!") case .theNewYork: print("New York!") default: fatalError("This can't be reached") }

Slide 79

Slide 79 text

enum class City { NEW_YORK, CHICAGO, NAPLES } let city = City.chicago switch city { case .chicago: print("Chicago!") case .naples: print("Naples!") case .newyork: print("New York!") }

Slide 80

Slide 80 text

enum class City { NEW_YORK, CHICAGO, NAPLES } let city = City(rawValue: ESKIOFramework.City.chicago) switch city { case .chicago: print("Chicago!") case .naples: print("Naples!") case .newyork: print("New York!") }

Slide 81

Slide 81 text

enum class City { NEW_YORK, CHICAGO, NAPLES, ANYWHERE } sealed class Pizza(val city: City) { object ThinCrust : Pizza(NEW_YORK) object DeepDish : Pizza(CHICAGO) object Neapolitan : Pizza(NAPLES) class Dessert(val topping: String): Pizza(ANYWHERE) }

Slide 82

Slide 82 text

enum City: RawRepresentable {a case chicago case newyork case naples init(rawValue: ESKIOFramework.City) { switch (rawValue){ case .theNewYork: self = .newyork case .chicago: self = .chicago case .naples: self = .naples default: fatalError("This can't be reached") } } var rawValue: ESKIOFramework.City { switch(self){ case .newyork: return .theNewYork case .chicago: return .chicago case .naples: return .naples } } }b

Slide 83

Slide 83 text

enum City: RawRepresentable {a case chicago case newyork case naples case anywhere init(rawValue: ESKIOFramework.City) { switch (rawValue){ case .theNewYork: self = .newyork case .chicago: self = .chicago case .naples: self = .naples case .anywhere: self = .anywhere default: fatalError("This can't be reached") } } var rawValue: ESKIOFramework.City { switch(self){ case .newyork: return .theNewYork case .chicago: return .chicago case .naples: return .naples case .anywhere: return .anywhere }

Slide 84

Slide 84 text

enum Pizza: RawRepresentable {a }b

Slide 85

Slide 85 text

enum Pizza: RawRepresentable {a case deepdish(City) case thin(City) case neapolitan(City) case dessert(City, String) }b

Slide 86

Slide 86 text

enum Pizza: RawRepresentable {a … init(rawValue: ESKIOFramework.Pizza) { switch (rawValue){ case .DeepDish(): self = .deepdish(City(rawValue: rawValue.city)) … case is ESKIOFramework.Pizza.Dessert: let dessert = (rawValue as! ESKIOFramework.Pizza.Dessert) self = .dessert(City(rawValue: rawValue.city), dessert.topping) default: fatalError("This can't be reached") } } var rawValue: ESKIOFramework.Pizza { switch(self){ case .deepdish: return .DeepDish() … case let .dessert(_, topping): return ESKIOFramework.Pizza.Dessert(topping: topping) } } }b

Slide 87

Slide 87 text

func printCity(city: City) { switch city { case .naples: print("Naples!") case .chicago: print("Chicago!") case .newyork: print("New Yawk!") case .anywhere: print("Anywhere!") } } func printPizza(pizza: Pizza) { switch pizza { case let .neapolitan(city): print("City: \(city)") case let .deepdish(city): print("City: \(city)") case let .thin(city): print("City: \(city)") case let .dessert(city, topping): print("City: \(city), Dessert: \(topping)") } }

Slide 88

Slide 88 text

New Yawk! Chicago! Naples! Anywhere! City: newyork City: naples City: chicago City: anywhere, Dessert: nutella

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

Generics

Slide 91

Slide 91 text

class StateHolder(state: T) { val myState = state fun pullState(): T = myState }

Slide 92

Slide 92 text

class StateHolder(state: T) { val myState = state fun pullState(): T = myState } let holder = StateHolder(state: "yo") let state = holder.pullState() print(state)

Slide 93

Slide 93 text

class StateHolder(state: T) { val myState = state fun pullState(): T = myState } let holder = StateHolder(state: "yo") let state = holder.pullState() print(state) Expression implicitly coerced `Any?` To `Any` _ .

Slide 94

Slide 94 text

__attribute__((objc_subclassing_restricted)) __attribute__((swift_name("StateHolder"))) @interface ESKIOFStateHolder : KotlinBase - (instancetype)initWithState:(id _Nullable)state __attribute__((swift_name("init(state:)"))) __attribute__((objc_designated_initializer)); - (id _Nullable)pullState __attribute__((swift_name("pullState()"))); @property (readonly) id _Nullable myState __attribute__((swift_name("myState"))); @end;

Slide 95

Slide 95 text

__attribute__((objc_subclassing_restricted)) __attribute__((swift_name("StateHolder"))) @interface ESKIOFStateHolder : KotlinBase - (instancetype)initWithState:(id _Nullable)state __attribute__((swift_name("init(state:)"))) __attribute__((objc_designated_initializer)); - (id _Nullable)pullState __attribute__((swift_name("pullState()"))); @property (readonly) id _Nullable myState __attribute__((swift_name("myState"))); @end;

Slide 96

Slide 96 text

class StateHolder(state: T) { val myState = state fun pullState(): T = myState } let holder = StateHolder(state: "yo") let state = holder.pullState() print(state) Expression implicitly coerced `Any?` To `Any` _ .

Slide 97

Slide 97 text

class StateHolder(state: T) { val myState = state fun pullState(): T = myState } let holder = StateHolder(state: "yo") let state = holder.pullState() print(state)

Slide 98

Slide 98 text

__attribute__((objc_subclassing_restricted)) __attribute__((swift_name("StateHolder"))) @interface ESKIOFStateHolder : KotlinBase - (instancetype)initWithState:(id _Nullable)state __attribute__((swift_name("init(state:)"))) __attribute__((objc_designated_initializer)); - (id _Nullable)pullState __attribute__((swift_name("pullState()"))); @property (readonly) id _Nullable myState __attribute__((swift_name("myState"))); @end;

Slide 99

Slide 99 text

__attribute__((objc_subclassing_restricted)) __attribute__((swift_name("StateHolder"))) @interface ESKIOFStateHolder : KotlinBase - (instancetype)initWithState:(id)state __attribute__((swift_name("init(state:)"))) __attribute__((objc_designated_initializer)); - (id)pullState __attribute__((swift_name("pullState()"))); @property (readonly) id myState __attribute__((swift_name("myState"))); @end;

Slide 100

Slide 100 text

class StateHolder(state: T) {…} fun copy(from: StateHolder, to: StateHolder) {…} @interface ESKIOFStateHolder<__covariant T>

Slide 101

Slide 101 text

No content

Slide 102

Slide 102 text

No content

Slide 103

Slide 103 text

value types

Slide 104

Slide 104 text

struct Address { varaline1: String varaline2: String? varacity: String varastate: String varazip: String }a

Slide 105

Slide 105 text

struct Address {…}a func test() { var me = Address( line1: "1455 Market St", line2: "Apt 1", city: "San Francisco", state: "CA", zip: "94103" ) var neighbor = me neighbor.line2 = "Apt 2" print("\(me ?? ""), \(neighbor ?? "")") // prints "Apt 1, Apt 2" }

Slide 106

Slide 106 text

class Person { var firstName: String = "John" var lastName: String = "Doe" } func test() { var john = Person() var jane = john jane.firstName = "Jane" print("\(john.firstName), \(jane.firstName)") // oops, both "Jane" }

Slide 107

Slide 107 text

struct Address { varaline1: String varaline2: String? varacity: String varastate: String varazip: String }a

Slide 108

Slide 108 text

data class Address( val line1: String, val line2: String?, val city: String, val state: String, val zip: String )

Slide 109

Slide 109 text

data class Address(…) fun test() { val me = Address( line1 = "1455 Market St", line2 = "Apt 1", city = "San Francisco", state = "CA", zip = "94103" ) val neighbor = me.copy(line2 = "Apt 2") print("$me, $neighbor") }

Slide 110

Slide 110 text

struct Struct { var name: String } let a = Struct(name: "jrod") a.name = "" data class Struct(var name: String) val a = Struct(name = "jrod") a.name = "" Cannot assign …: 'a' is a 'let' constant _

Slide 111

Slide 111 text

class Point( val x: Int, val y: Int )

Slide 112

Slide 112 text

class Point( val x: Int, val y: Int ) value class Point( val x: Int, val y: Int ) Today Someday?

Slide 113

Slide 113 text

header header x y header x y header x y header x y val points = arrayOf(Point(1, 2), …)

Slide 114

Slide 114 text

header x x x x y y y y val points = arrayOf(Point(1, 2), …)

Slide 115

Slide 115 text

No content

Slide 116

Slide 116 text

No content

Slide 117

Slide 117 text

Build performance

Slide 118

Slide 118 text

No content

Slide 119

Slide 119 text

No content

Slide 120

Slide 120 text

No content

Slide 121

Slide 121 text

No content

Slide 122

Slide 122 text

No content

Slide 123

Slide 123 text

$ ./gradlew :SharedCode:packForXCode \
 -—profile --rerun-tasks -—no-build-cache -—console=plain

Slide 124

Slide 124 text

$ ./gradlew :SharedCode:packForXCode \
 -—profile --rerun-tasks -—no-build-cache -—console=plain

Slide 125

Slide 125 text

No content

Slide 126

Slide 126 text

No content

Slide 127

Slide 127 text

No content

Slide 128

Slide 128 text

http://bit.ly/34ZN5UQ

Slide 129

Slide 129 text

https://github.com/JetBrains/kotlin/blob/master/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/ jetbrains/kotlin/gradle/tasks/Tasks.kt#L128

Slide 130

Slide 130 text

Runtime performance

Slide 131

Slide 131 text

fun mergesort(list: List): List { if (list.size <= 1) return list val middle = list.size / 2 val left = list.subList(0, middle) val right = list.subList(middle, list.size) return merge(mergesort(left), mergesort(right)) } fun merge(left: List, right: List): List { var iLeft = 0 var iRight = 0 val newList = mutableListOf() while (iLeft < left.size && iRight < right.size) { if (left[iLeft] <= right[iRight]) newList.add(left[iLeft++]) else newList.add(right[iRight++]) } while (iLeft < left.size) newList.add(left[iLeft++]) while (iRight < right.size) newList.add(right[iRight++]) return newList }

Slide 132

Slide 132 text

No content

Slide 133

Slide 133 text

No content

Slide 134

Slide 134 text

No content

Slide 135

Slide 135 text

No content

Slide 136

Slide 136 text

No content

Slide 137

Slide 137 text

No content

Slide 138

Slide 138 text

No content

Slide 139

Slide 139 text

No content

Slide 140

Slide 140 text

No content

Slide 141

Slide 141 text

No content

Slide 142

Slide 142 text

No content

Slide 143

Slide 143 text

No content

Slide 144

Slide 144 text

https://bit.ly/32DOCyf

Slide 145

Slide 145 text

No content

Slide 146

Slide 146 text

No content

Slide 147

Slide 147 text

No content

Slide 148

Slide 148 text

Recap

Slide 149

Slide 149 text

• Beware of Int! (Swift -> Kotlin)

Slide 150

Slide 150 text

• Beware of Int! (Swift -> Kotlin) • Beware of Method overloads with similar parameter names

Slide 151

Slide 151 text

• Beware of Int! (Swift -> Kotlin) • Beware of Method overloads with similar parameter names • Let's continue to grow the core Multiplatform suite of libraries!

Slide 152

Slide 152 text

• Beware of Int! (Swift -> Kotlin) • Beware of Method overloads with similar parameter names • Let's continue to grow the core Multiplatform suite of libraries! • Enums matter! But currently a sore spot in today's interop story

Slide 153

Slide 153 text

• Beware of Int! (Swift -> Kotlin) • Beware of Method overloads with similar parameter names • Let's continue to grow the core Multiplatform suite of libraries! • Enums matter! But currently a sore spot in today's interop story • JetBrains Swift Codegen?!

Slide 154

Slide 154 text

• Beware of Int! (Swift -> Kotlin) • Beware of Method overloads with similar parameter names • Let's continue to grow the core Multiplatform suite of libraries! • Enums matter! But currently a sore spot in today's interop story • JetBrains Swift Codegen?! • On the other hand, Generics seem to favor Obj-C more

Slide 155

Slide 155 text

• Beware of Int! (Swift -> Kotlin) • Beware of Method overloads with similar parameter names • Let's continue to grow the core Multiplatform suite of libraries! • Enums matter! But currently a sore spot in today's interop story • JetBrains Swift Codegen?! • On the other hand, Generics seem to favor Obj-C more • No matter what progress is made, lack of value types is still a limiting factor

Slide 156

Slide 156 text

• Beware of Int! (Swift -> Kotlin) • Beware of Method overloads with similar parameter names • Let's continue to grow the core Multiplatform suite of libraries! • Enums matter! But currently a sore spot in today's interop story • JetBrains Swift Codegen?! • On the other hand, Generics seem to favor Obj-C more • No matter what progress is made, lack of value types is still a limiting factor • Build performance could be better, looking forward to native compiler improvements in 1.4

Slide 157

Slide 157 text

• Beware of Int! (Swift -> Kotlin) • Beware of Method overloads with similar parameter names • Let's continue to grow the core Multiplatform suite of libraries! • Enums matter! But currently a sore spot in today's interop story • JetBrains Swift Codegen?! • On the other hand, Generics seem to favor Obj-C more • No matter what progress is made, lack of value types is still a limiting factor • Build performance could be better, looking forward to native compiler improvements in 1.4 • Need that build cache issue fix removing @LocalState!

Slide 158

Slide 158 text

• Beware of Int! (Swift -> Kotlin) • Beware of Method overloads with similar parameter names • Let's continue to grow the core Multiplatform suite of libraries! • Enums matter! But currently a sore spot in today's interop story • JetBrains Swift Codegen?! • On the other hand, Generics seem to favor Obj-C more • No matter what progress is made, lack of value types is still a limiting factor • Build performance could be better, looking forward to native compiler improvements in 1.4 • Need that build cache issue fix removing @LocalState! • Runtime performance isn't too bad for normal app cases, but heavy computation pays a heavier price

Slide 159

Slide 159 text

• Beware of Method overloads with similar parameter names • Let's continue to grow the core Multiplatform suite of libraries! • Enums matter! But currently a sore spot in today's interop story • JetBrains Swift Codegen?! • On the other hand, Generics seem to favor Obj-C more • No matter what progress is made, lack of value types is still a limiting factor • Build performance could be better, looking forward to native compiler improvements in 1.4 • Need that build cache issue fix removing @LocalState! • Runtime performance isn't too bad for normal app cases, but heavy computation pays a heavier price * Future continues to look promising for Swift-ObjC-Kotlin interop. Wire support for iOS a target for 2020.

Slide 160

Slide 160 text

@jrodbx

Slide 161

Slide 161 text

#KotlinConf THANK YOU AND REMEMBER TO VOTE John Rodriguez @jrodbx