Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin != Swift

Kotlin != Swift

Two modern languages critical to native mobile development with similar language features and subtle differences. In this talk we’ll quickly refresh the basic syntax structures between Swift and Kotlin, and then explore some of the more important conceptual nuances.

If you find yourself working in two native iOS and Android codebases, then this talk is for you! Guard, swizzle, retain cycles and memory management, struct, argument labels, and whatever else we can fit in between.

jacksoncheek

November 12, 2019
Tweet

More Decks by jacksoncheek

Other Decks in Programming

Transcript

  1. @jacksoncheek let name: String = "Jackson Cheek" print("My name is

    \(name)") // My name is Jackson Cheek val name: String = "Jackson Cheek” print("My name is $name”) // My name is Jackson Cheek Swift Kotlin
  2. @jacksoncheek enum Language { case kotlin case swift case java

    case objective_c } enum class Language { KOTLIN, SWIFT, JAVA, OBJECTIVE_C } Swift Kotlin
  3. @jacksoncheek enum class Language(name: String) { KOTLIN("kotlin"), SWIFT("swift"), JAVA("java"), OBJECTIVE_C("objective-c")

    } enum Language: String { case kotlin = "kotlin" case swift = "swift" case java = "java" case objective_c = "objective-c" } Swift Kotlin
  4. @jacksoncheek protocol Developer { func languages() -> Set<Language> } interface

    Developer { fun languages(): Set<Language> } Swift Kotlin
  5. @jacksoncheek class Person { let name: String let languages: Array<Language>

    init(name: String, _ languages: Language...) { self.name = name self.languages = languages } } class Person( val name: String, vararg val languages: Language ) { } Swift Kotlin
  6. @jacksoncheek class Person: Developer { let name: String let languages:

    Array<Language> init(name: String, _ languages: Language...) { self.name = name self.languages = languages } } class Person( val name: String, vararg val languages: Language ): Developer { } Swift Kotlin
  7. @jacksoncheek class Person: Developer { let name: String let languages:

    Array<Language> init(name: String, _ languages: Language...) { self.name = name self.languages = languages } func languages() -> Set<Language> { } } class Person( val name: String, vararg val languages: Language ): Developer { override fun languages(): Set<Language> { } } Swift Kotlin
  8. @jacksoncheek class Person: Developer { let name: String let languages:

    Array<Language> init(name: String, _ languages: Language...) { self.name = name self.languages = languages } func languages() -> Set<Language> { var unique: Set<Language> = Set() return unique } } class Person( val name: String, vararg val languages: Language ): Developer { override fun languages(): Set<Language> { val unique: Set<Language> = setOf() return unique } } Swift Kotlin
  9. @jacksoncheek class Person: Developer { let name: String let languages:

    Array<Language> init(name: String, _ languages: Language...) { self.name = name self.languages = languages } func languages() -> Set<Language> { var unique: Set<Language> = Set() for language in _languages { } return unique } } class Person( val name: String, vararg val languages: Language ): Developer { override fun languages(): Set<Language> { val unique: Set<Language> = setOf() for (language in languages) { } return unique } } Swift Kotlin
  10. @jacksoncheek class Person: Developer { let name: String let languages:

    Array<Language> init(name: String, _ languages: Language...) { self.name = name self.languages = languages } func languages() -> Set<Language> { var unique: Set<Language> = Set() for language in _languages { unique.insert(language) } return unique } } class Person( val name: String, vararg val languages: Language ): Developer { override fun languages(): Set<Language> { val unique: Set<Language> = setOf() for (language in languages) { unique.plus(language) } return unique } } Swift Kotlin
  11. @jacksoncheek let jackson: Person = Person( name: "Jackson Cheek", .kotlin,

    .java, .swift ) val jackson: Person = Person( "Jackson Cheek", Language.KOTLIN, Language.JAVA, Language.SWIFT ) Swift Kotlin
  12. @jacksoncheek var optName: String? = "Jackson Cheek" guard let name

    = optName else { print("Oops") return } print("My name is \(name)") // My name is Jackson Cheek Swift
  13. @jacksoncheek var optName: String? = "Jackson Cheek" guard let name

    = optName else { print("Oops") return } print("My name is \(name)") // My name is Jackson Cheek var optName: String? = "Jackson Cheek" val name = optName?.let { it } if (name != null) { print("My name is $name") } else { print("Oops") } // My name is Jackson Cheek Swift Kotlin
  14. @jacksoncheek var optName: String? = "Jackson Cheek" let age =

    30 guard let name = optName, age > 21 else { print("Conditions not met") return } print("Conditions met”) // Conditions met Swift
  15. @jacksoncheek var optName: String? = "Jackson Cheek" let age =

    30 guard let name = optName, age > 21 else { print("Conditions not met") return } print("Conditions met”) // Conditions met var optName: String? = "Jackson Cheek" val age = 30 val name = optName?.let { it } if (name != null && age > 21) { print("Conditions met") } else { print("Conditions not met") } // Conditions met Swift Kotlin
  16. @jacksoncheek • viewDidLoad • viewWillAppear • viewDidAppear • viewWillDisappear •

    viewDidDisappear Product Manager: “I want to track every time a user lands on a new screen!”
  17. @jacksoncheek @objc func swizzledViewDidAppear() { guard let screenName = className

    else { return } analyticsService.trackScreen(screenName: screenName) } Swift
  18. @jacksoncheek @objc func swizzledViewDidAppear() { guard let screenName = className

    else { return } analyticsService.trackScreen(screenName: screenName) } class func swizzle() { guard self === UIViewController.self else { return } let original = class_getInstanceMethod( self, #selector(viewDidAppear(_:)) ) } Swift
  19. @jacksoncheek @objc func swizzledViewDidAppear() { guard let screenName = className

    else { return } analyticsService.trackScreen(screenName: screenName) } class func swizzle() { guard self === UIViewController.self else { return } let original = class_getInstanceMethod( self, #selector(viewDidAppear(_:)) ) } #selector Reference to method in compiled code Swift
  20. @jacksoncheek @objc func swizzledViewDidAppear() { guard let screenName = className

    else { return } analyticsService.trackScreen(screenName: screenName) } class func swizzle() { guard self === UIViewController.self else { return } let original = class_getInstanceMethod( self, #selector(viewDidAppear(_:)) ) let swizzled = class_getInstanceMethod( self, #selector(swizzledViewDidAppear) ) } Swift
  21. @jacksoncheek @objc func swizzledViewDidAppear() { guard let screenName = className

    else { return } analyticsService.trackScreen(screenName: screenName) } class func swizzle() { guard self === UIViewController.self else { return } let original = class_getInstanceMethod( self, #selector(viewDidAppear(_:)) ) let swizzled = class_getInstanceMethod( self, #selector(swizzledViewDidAppear) ) method_exchangeImplementations(original!, swizzled!) } Swift
  22. @jacksoncheek • No garbage collector • Automatic Reference Counting •

    Memory allocated for an object when initialized Memory Management
  23. @jacksoncheek • No garbage collector • Automatic Reference Counting •

    Memory allocated for an object when initialized • Memory deallocated when there are no more strong references to that object Memory Management
  24. @jacksoncheek • No garbage collector • Automatic Reference Counting •

    Memory allocated for an object when initialized • Memory deallocated when there are no more strong references to that object • Leak when all references aren’t cleaned up Memory Management
  25. @jacksoncheek class Person { let name: String var phone: Phone?

    = nil init(name: String) { self.name = name } } class Phone { let model: String var owner: Person? = nil init(model: String) { self.model = model } } Swift
  26. @jacksoncheek class Person { let name: String var phone: Phone?

    = nil init(name: String) { self.name = name } } class Phone { let model: String var owner: Person? = nil init(model: String) { self.model = model } } var jackson: Person? = Person(name: "Jackson") var pixel3: Phone? = Phone(model: "Pixel 3") Swift
  27. @jacksoncheek class Person { let name: String var phone: Phone?

    = nil init(name: String) { self.name = name } } class Phone { let model: String var owner: Person? = nil init(model: String) { self.model = model } } var jackson: Person? = Person(name: "Jackson") var pixel3: Phone? = Phone(model: "Pixel 3") jackson!.phone = pixel3 pixel3!.owner = jackson Swift
  28. @jacksoncheek var jackson var pixel3 <Person Instance> name: “Jackson” phone:

    nil <Phone Instance> model: “Pixel 3” owner: nil strong strong 1 1 var jackson: Person? = Person(name: "Jackson") var pixel3: Phone? = Phone(model: "Pixel 3") Swift
  29. @jacksoncheek var jackson var pixel3 <Person Instance> name: “Jackson” phone:

    <Phone> <Phone Instance> model: “Pixel 3” owner: <Person> strong strong strong strong 2 2 var jackson: Person? = Person(name: "Jackson") var pixel3: Phone? = Phone(model: "Pixel 3") jackson!.phone = pixel3 pixel3!.owner = jackson Swift
  30. @jacksoncheek var jackson var pixel3 strong strong <Person Instance> name:

    “Jackson” phone: <Phone> <Phone Instance> model: “Pixel 3” owner: <Person> 1 1 var jackson: Person? = Person(name: "Jackson") var pixel3: Phone? = Phone(model: "Pixel 3") jackson!.phone = pixel3 pixel3!.owner = jackson jackson = nil pixel3 = nil Swift
  31. @jacksoncheek class Phone { let model: String weak var owner:

    Person? = nil init(model: String) { self.model = model } } Swift var jackson var pixel3 <Person Instance> name: “Jackson” phone: <Phone> <Phone Instance> model: “Pixel 3” owner: <Person> strong strong strong strong 2 2
  32. @jacksoncheek var jackson var pixel3 <Person Instance> name: “Jackson” phone:

    <Phone> <Phone Instance> model: “Pixel 3” owner: <Person> strong strong strong weak 1 2 class Phone { let model: String weak var owner: Person? = nil init(model: String) { self.model = model } } Swift
  33. @jacksoncheek var jackson var pixel3 <Person Instance> name: “Jackson” phone:

    <Phone> <Phone Instance> model: “Pixel 3” owner: <Person> strong strong weak 0 2 jackson = nil Swift
  34. @jacksoncheek jackson = nil Swift var jackson var pixel3 strong

    <Phone Instance> model: “Pixel 3” owner: nil 1
  35. @jacksoncheek struct State { var isLoading: Bool } data class

    State( var isLoading: Boolean ) Swift Kotlin
  36. @jacksoncheek struct State { var isLoading: Bool } var initial

    = State(isLoading: false) data class State( var isLoading: Boolean ) var initial = State(isLoading = false) Swift Kotlin
  37. @jacksoncheek struct State { var isLoading: Bool } var initial

    = State(isLoading: false) var copy = initial data class State( var isLoading: Boolean ) var initial = State(isLoading = false) var copy = initial Swift Kotlin
  38. @jacksoncheek struct State { var isLoading: Bool } var initial

    = State(isLoading: false) var copy = initial initial.isLoading = true data class State( var isLoading: Boolean ) var initial = State(isLoading = false) var copy = initial initial.isLoading = true Swift Kotlin
  39. @jacksoncheek struct State { var isLoading: Bool } var initial

    = State(isLoading: false) var copy = initial initial.isLoading = true print("Loading state: \(copy.isLoading)") // Loading state: false data class State( var isLoading: Boolean ) var initial = State(isLoading = false) var copy = initial initial.isLoading = true print("Loading state: ${copy.isLoading}") // Loading state: true Swift Kotlin
  40. @jacksoncheek enum AccountType { case credit case debit } class

    Shopper { func payBill(accountType: AccountType) { print("Thank you!") } } enum class AccountType { CREDIT, DEBIT } class Shopper { fun payBill(accountType: AccountType) { print("Thank you!") } } Swift Kotlin
  41. @jacksoncheek enum AccountType { case credit case debit } class

    Shopper { func payBill(accountType: AccountType) { print("Thank you!") } } let shopper: Shopper = Shopper() shopper.payBill(accountType: .credit) // Thank you! enum class AccountType { CREDIT, DEBIT } class Shopper { fun payBill(accountType: AccountType) { print("Thank you!") } } val shopper: Shopper = Shopper() shopper.payBill(accountType = CREDIT) // Thank you! Swift Kotlin
  42. @jacksoncheek enum AccountType { case credit case debit } class

    Shopper { func payBill(_ accountType: AccountType) { print("Thank you!") } } let shopper: Shopper = Shopper() shopper.payBill(.credit) // Thank you! enum class AccountType { CREDIT, DEBIT } class Shopper { fun payBill(accountType: AccountType) { print("Thank you!") } } val shopper: Shopper = Shopper() shopper.payBill(CREDIT) // Thank you! Swift Kotlin
  43. @jacksoncheek enum AccountType { case credit case debit } class

    Shopper { func payBill(with accountType: AccountType) { print("Thank you!”) } } let shopper: Shopper = Shopper() shopper.payBill(with: .credit) // Thank you! enum class AccountType { CREDIT, DEBIT } class Shopper { fun payBill(with accountType: AccountType) { print("Thank you!") } } val shopper: Shopper = Shopper() shopper.payBill(with = CREDIT) // Not possible! ❌ Swift Kotlin