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

Kotlin & Swift: Convergent Evolution? (Video)

Kotlin & Swift: Convergent Evolution? (Video)

At Google I/O this year, the Android team announced first-class support for Kotlin! Kotlin is a modern and compact language that looks and feels very similar to Apple’s Swift. Both are rapidly rising in popularity. Once you’ve learned one of these two languages, the barriers to becoming a cross-platform (native) mobile developer are significantly reduced. Join me for a journey through the two languages, and leave inspired to learn one, then both, then to conquer the entire (mobile) world!

Venue: Android Summit 2017, http://androidsummit.org/

3a6060bc7ace07fa75791cd5dac2d46a?s=128

Stuart Kent

August 25, 2017
Tweet

Transcript

  1. @skentphd Kotlin & Swift Convergent Evolution?

  2. @skentphd Kotlin & Swift Convergent Evolution? Simultaneous Invention!

  3. @skentphd Me Stuart Kent Detroit Labs @skentphd

  4. @skentphd Me Stuart Kent Detroit Labs @skentphd

  5. @skentphd Me Stuart Kent Detroit Labs @skentphd @skentphd

  6. @skentphd Me Android Java iOS Swift Kotlin 2014 2015 2016

    2017
  7. @skentphd Me Android Java iOS Swift Kotlin 2014 2015 2016

    2017
  8. @skentphd Me Android Java iOS Swift Kotlin 2014 2015 2016

    2017
  9. @skentphd Me Android Java iOS Swift Kotlin 2014 2015 2016

    2017
  10. @skentphd You • 90% heard of Kotlin • 50% used

    Kotlin • 15% written Kotlin on Android • 10% written Kotlin in production
  11. @skentphd You • 90% heard of Kotlin • 50% used

    Kotlin • 15% written Kotlin on Android • 10% written Kotlin in production
  12. @skentphd Android & iOS

  13. @skentphd Commonalities • Lifecycle • Networking • Accessibility • Background

    processing • Security
  14. @skentphd Convergences • Platform-agnostic architectures: MVP, MVVM

  15. @skentphd Convergences • Platform-agnostic architectures: MVP, MVVM • Layout components:

    • LinearLayout <-> UIStackView • ConstraintLayout <-> AutoLayout
  16. @skentphd Convergences • Platform-agnostic architectures: MVP, MVVM • Layout components:

    • LinearLayout <-> UIStackView • ConstraintLayout <-> AutoLayout • Development languages
  17. @skentphd Claim It's never been easier for a native Android

    developer to learn native iOS development.
  18. @skentphd Calls To Action As Android developers, you should consider

    • learning Kotlin; then • learning Swift & iOS $
  19. @skentphd Kotlin & Swift

  20. @skentphd Kotlin & Swift • Strikingly similar principles and implementations:

    • Accessibility • Expressivity • Safety • Developed ~simultaneously but independently
  21. @skentphd Kotlin & Swift: Accessibility • Both: "vanilla" syntax •

    Both: gradual adoption via interoperability • Both: excellent documentation • Kotlin: semi-automatic migration • Swift: manual migration
  22. @skentphd Kotlin & Swift: Accessibility • Both: "vanilla" syntax •

    Both: gradual adoption via interoperability • Both: excellent documentation • Kotlin: semi-automatic migration • Swift: manual migration
  23. @skentphd Basic Syntax • Both: nothing too weird; "braces not

    spaces"
  24. @skentphd Kotlin 1.1.4 // Declarations val summit = "Android Summit"

    // Declarations let summit = "Android Summit" Swift 4
  25. @skentphd Kotlin 1.1.4 // Declarations val summit = "Android Summit"

    fun greet(name: String): String { return "Hello, \{name}!" } // Declarations let summit = "Android Summit" func greet(name: String) -> String { return "Hello, \(name)!" } Swift 4
  26. @skentphd Kotlin 1.1.4 // Declarations val summit = "Android Summit"

    fun greet(name: String): String { return "Hello, \{name}!" } // Usage greet(name = summit) // "Hello, Android Summit!" // Declarations let summit = "Android Summit" func greet(name: String) -> String { return "Hello, \(name)!" } // Usage greet(name: summit) // "Hello, Android Summit!" Swift 4
  27. @skentphd Kotlin // Declarations val summit = "Android Summit" var

    spaceCount = 0 var letterCount = 0 // Usage for (char in summit) { if (char == ' ') { spaceCount += 1 } else { letterCount += 1 } } spaceCount // 1 letterCount // 13 // Declarations let summit = "Android Summit" var spaceCount = 0 var letterCount = 0 // Usage for char in summit { if char == " " { spaceCount += 1 } else { letterCount += 1 } } spaceCount // 1 letterCount // 13 Swift
  28. @skentphd Kotlin // Declarations val summit = "Android Summit" var

    spaceCount = 0 var letterCount = 0 // Usage for (char in summit) { if (char == ' ') { spaceCount += 1 } else { letterCount += 1 } } spaceCount // 1 letterCount // 13 // Declarations let summit = "Android Summit" var spaceCount = 0 var letterCount = 0 // Usage for char in summit { if char == " " { spaceCount += 1 } else { letterCount += 1 } } spaceCount // 1 letterCount // 13 Swift
  29. @skentphd Kotlin // Declarations interface Listener { fun notify() }

    // Declarations protocol Listener { func notify() } Swift
  30. @skentphd Kotlin // Declarations interface Listener { fun notify() }

    class AnyClass : Listener { override fun notify() { // Logic } } // Declarations protocol Listener { func notify() } class AnyClass : Listener { func notify() { // Logic } } Swift
  31. @skentphd Kotlin // Declarations interface Listener { fun notify() }

    class AnyClass : Listener { override fun notify() { // Logic } } // Usage val anyClass: Listener = AnyClass() anyClass.notify() // Declarations protocol Listener { func notify() } class AnyClass : Listener { func notify() { // Logic } } // Usage let anyClass: Listener = AnyClass() anyClass.notify() Swift
  32. @skentphd Anticlimactic = Awesome

  33. @skentphd Kotlin & Swift: Expressivity • Both: extension of closed

    source types • Both: fluent collection operators • Both: defaults shrink API surface areas • Both: algebraic data types • Both: first class functions • Both: amplify signal; reduce noise (boilerplate--)
  34. @skentphd Kotlin & Swift: Expressivity • Both: extension of closed

    source types • Both: fluent collection operators • Both: defaults shrink API surface areas • Both: algebraic data types • Both: first class functions • Both: amplify signal; reduce noise (boilerplate--)
  35. @skentphd Kotlin & Swift: Expressivity • Both: extension of closed

    source types • Both: fluent collection operators • Both: defaults shrink API surface areas • Both: algebraic data types • Both: first class functions • Both: amplify signal; reduce noise (boilerplate--)
  36. @skentphd Extensions • Both: more discoverable utility methods • Both:

    fluent expression of domain concepts • Both: completeness of standard library • Both: minimize cross-platform differences
  37. @skentphd Extensions • Both: more discoverable utility methods • Both:

    fluent expression of domain concepts • Both: completeness of standard library • Both: minimize cross-platform differences
  38. @skentphd Java 7 // Declarations public final class PasswordUtil {

    public static boolean isValidPassword(String candidate) { // Logic } private PasswordUtil() { // No instances } }
  39. @skentphd Java 7 // Declarations public final class PasswordUtil {

    public static boolean isValidPassword(String candidate) { // Logic } private PasswordUtil() { // No instances } } // Usage if (PasswordUtil.isValidPassword("swordfish")) { // I have to *know* this exists! // Conditional logic }
  40. @skentphd Kotlin // Declarations fun String.isValidPassword():Boolean { return this ==

    "swordfish" } // Declarations extension String { func isValidPassword() -> Bool { return self == "swordfish" } } Swift
  41. @skentphd Kotlin // Declarations fun String.isValidPassword():Boolean { return this ==

    "swordfish" } // Declarations extension String { func isValidPassword() -> Bool { return self == "swordfish" } } Swift
  42. @skentphd Kotlin // Declarations fun String.isValidPassword():Boolean { return this ==

    "swordfish" } // Declarations extension String { func isValidPassword() -> Bool { return self == "swordfish" } } Swift
  43. @skentphd Kotlin // Declarations fun String.isValidPassword():Boolean { return this ==

    "swordfish" } // Usage if ("swordfish".isValidPassword()) { // Conditional logic } // Declarations extension String { func isValidPassword() -> Bool { return self == "swordfish" } } // Usage if "swordfish".isValidPassword() { // Conditional logic } Swift
  44. @skentphd Collection Operations • Both: readable -> understandable • Both:

    flexible -> maintainable • Both: robust • Java: streams available in 8+ • Android: streams available for minSdk 24+
  45. @skentphd Collection Operations • Both: readable -> understandable • Both:

    flexible -> maintainable • Both: robust • Java: streams available in 8+ • Android: streams available for minSdk 24+
  46. @skentphd Java // Declarations List<Integer> list = Arrays.asList("1", "2", "3",

    "4"); String joinedList = ""; // Usage for (int index = 0; index > list.size(); index++) { joinedList += list.get(index); if (index < list.size() - 1) { joinedList += ", "; } } joinedList // "1, 2, 3, 4"
  47. @skentphd Kotlin // Declarations val list = listOf("1", "2", "3",

    "4") // Usage list.joinToString() // "1, 2, 3, 4" // Declarations let list = ["1", "2", "3", "4"] // Usage list.joined(separator: ", ") // "1, 2, 3, 4" Swift
  48. @skentphd Kotlin // Declarations val orders: List<Order> // Usage orders

    .map { it.dateString } .filter { it < "2017-01-01" } .sorted() .reversed() .drop(10) .take(5) // Declarations let orders: = [Order] // Usage orders .map { $0.dateString } .filter { $0 < "2017-01-01" } .sorted() .reversed() .dropFirst(10) .prefix(5) Swift
  49. @skentphd Kotlin // Declarations val orders: List<Order> // Usage orders

    .map { it.dateString } .filter { it < "2017-01-01" } .sorted() .reversed() .drop(10) .take(5) // Declarations let orders: = [Order] // Usage orders .map { $0.dateString } .filter { $0 < "2017-01-01" } .sorted() .reversed() .dropFirst(10) .prefix(5) Swift
  50. @skentphd Kotlin // Declarations val orders: List<Order> // Usage orders

    .map { it.dateString } .filter { it < "2017-01-01" } .sorted() .reversed() .drop(10) .take(5) // Declarations let orders: = [Order] // Usage orders .map { $0.dateString } .filter { $0 < "2017-01-01" } .sorted() .reversed() .dropFirst(10) .prefix(5) Swift
  51. @skentphd Kotlin // Declarations val orders: List<Order> // Usage orders

    .map { it.dateString } .filter { it < "2017-01-01" } .sorted() .reversed() .drop(10) .take(5) // Declarations let orders: = [Order] // Usage orders .map { $0.dateString } .filter { $0 < "2017-01-01" } .sorted() .reversed() .dropFirst(10) .prefix(5) Swift
  52. @skentphd Kotlin // Declarations val orders: List<Order> // Usage orders

    .map { it.dateString } .filter { it < "2017-01-01" } .sorted() .reversed() .drop(10) .take(5) // Declarations let orders: = [Order] // Usage orders .map { $0.dateString } .filter { $0 < "2017-01-01" } .sorted() .reversed() .dropFirst(10) .prefix(5) Swift
  53. @skentphd Kotlin // Declarations val orders: List<Order> // Usage orders

    .map { it.dateString } .filter { it < "2017-01-01" } .sorted() .reversed() .drop(10) .take(5) // Declarations let orders: = [Order] // Usage orders .map { $0.dateString } .filter { $0 < "2017-01-01" } .sorted() .reversed() .dropFirst(10) .prefix(5) Swift
  54. @skentphd Kotlin // Declarations val orders: List<Order> // Usage orders

    .map { it.dateString } .filter { it < "2017-01-01" } .sorted() .reversed() .drop(10) .take(5) // Declarations let orders: = [Order] // Usage orders .map { $0.dateString } .filter { $0 < "2017-01-01" } .sorted() .reversed() .dropFirst(10) .prefix(5) Swift
  55. @skentphd Kotlin // Declarations val orders: List<Order> // Usage orders

    .map { it.dateString } .filter { it < "2017-01-01" } .sorted() .reversed() .drop(10) .take(5) // Declarations let orders: = [Order] // Usage orders .map { $0.dateString } .filter { $0 < "2017-01-01" } .sorted() .reversed() .dropFirst(10) .prefix(5) Swift
  56. @skentphd Default Parameter Values • Both: improve call-site clarity •

    Both: shrink & simplify utility APIs • Both: replace builders • Both: allow cleaner manual dependency injection
  57. @skentphd Default Parameter Values • Both: improve call-site clarity •

    Both: shrink & simplify utility APIs • Both: replace builders • Both: allow cleaner manual dependency injection
  58. @skentphd Kotlin fun <T> Iterable<T>.joinToString( separator: CharSequence = ", ",

    prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String { /* Logic */ }
  59. @skentphd Kotlin fun <T> Iterable<T>.joinToString( separator: CharSequence = ", ",

    prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String { /* Logic */ }
  60. @skentphd Kotlin fun <T> Iterable<T>.joinToString( separator: CharSequence = ", ",

    prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String { /* Logic */ }
  61. @skentphd Kotlin fun <T> Iterable<T>.joinToString( separator: CharSequence = ", ",

    prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String { /* Logic */ } listOf(1, 2, 3, 4).joinToString() // "1, 2, 3, 4" listOf(1, 2, 3, 4).joinToString(separator = " & ") // "1 & 2 & 3 & 4" listOf(1, 2, 3, 4).joinToString(prefix = "(", postfix = ")") // "(1, 2, 3, 4)"
  62. @skentphd Kotlin fun <T> Iterable<T>.joinToString( separator: CharSequence = ", ",

    prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String { /* Logic */ } listOf(1, 2, 3, 4).joinToString() // "1, 2, 3, 4" listOf(1, 2, 3, 4).joinToString(separator = " & ") // "1 & 2 & 3 & 4" listOf(1, 2, 3, 4).joinToString(prefix = "(", postfix = ")") // "(1, 2, 3, 4)" Java How many methods?
  63. @skentphd Kotlin fun <T> Iterable<T>.joinToString( separator: CharSequence = ", ",

    prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String { /* Logic */ } listOf(1, 2, 3, 4).joinToString() // "1, 2, 3, 4" listOf(1, 2, 3, 4).joinToString(separator = " & ") // "1 & 2 & 3 & 4" listOf(1, 2, 3, 4).joinToString(prefix = "(", postfix = ")") // "(1, 2, 3, 4)" Java 26 = 64 methods... plus name collisions!
  64. @skentphd Swift extension Collection where Element: CustomStringConvertible { func joinToString(

    separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "...", transform: ((Element) -> String)? = nil) -> String { /* Logic */ } }
  65. @skentphd Swift extension Collection where Element: CustomStringConvertible { func joinToString(

    separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "...", transform: ((Element) -> String)? = nil) -> String { /* Logic */ } }
  66. @skentphd Swift extension Collection where Element: CustomStringConvertible { func joinToString(

    separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "...", transform: ((Element) -> String)? = nil) -> String { /* Logic */ } }
  67. @skentphd Swift extension Collection where Element: CustomStringConvertible { func joinToString(

    separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "...", transform: ((Element) -> String)? = nil) -> String { /* Logic */ } } [1, 2, 3, 4].joinToString() // "1, 2, 3, 4" [1, 2, 3, 4].joinToString(separator: " & ") // "1 & 2 & 3 & 4" [1, 2, 3, 4].joinToString(prefix: "(", postfix: ")") // "(1, 2, 3, 4)"
  68. @skentphd Kotlin & Swift: Safety • Both: statically typed •

    Both: force developers to confront nullability • Both: force developers to confront mutability • Kotlin: immutable views of mutable collections • Kotlin: data classes with synthetic copy methods • Swift: custom value types
  69. @skentphd Kotlin & Swift: Safety • Both: statically typed •

    Both: force developers to confront nullability • Both: force developers to confront mutability • Kotlin: immutable views of mutable collections • Kotlin: data classes with synthetic copy methods • Swift: custom value types
  70. @skentphd Explicit Nullability

  71. @skentphd Java // Declarations String s1; // No nullability information

    by default // Usage s1.length(); // Could evaluate to a number; could crash the entire app
  72. "I call it my billion-dollar mistake. It was the invention

    of the null reference in 1965."
  73. @skentphd Java // Declarations @NonNull String s1; // Opt-in nullability

    information @Nullable String s2; // Opt-in nullability information
  74. @skentphd Java // Declarations @NonNull String s1; // Opt-in nullability

    information @Nullable String s2; // Opt-in nullability information // Usage s1.length(); // Presumed safe; no warning s2.length(); // Possibly unsafe; warning only if (s2 != null) { s2.length(); // Now safe(ish); no warning }
  75. "Remove barriers that make it hard to make better choices."

  76. "The trillion dollar mistake: assuming the billion dollar mistake of

    null is its existence, and not the absence of support in the type system."
  77. @skentphd Kotlin // Declarations var s1: String = "Hello, world!"

    var s2: String? = "Hello, world!" // Declarations var s1: String = "Hello, world!" var s2: String? = "Hello, world!" Swift
  78. @skentphd Kotlin // Declarations var s1: String = "Hello, world!"

    var s2: String? = "Hello, world!" // Declarations var s1: String = "Hello, world!" var s2: String? = "Hello, world!" Swift
  79. @skentphd Kotlin // Declarations var s1: String = "Hello, world!"

    var s2: String? = "Hello, world!" // Usage s1 = null // Does not compile! s2 = null // Compiles // Declarations var s1: String = "Hello, world!" var s2: String? = "Hello, world!" // Usage s1 = nil // Does not compile! s2 = nil // Compiles Swift
  80. @skentphd Kotlin // Declarations var s1: String = "Hello, world!"

    var s2: String? = "Hello, world!" // Usage s1.first() // Compiles s2.first() // Does not compile! // Declarations var s1: String = "Hello, world!" var s2: String? = "Hello, world!" // Usage s1.first // Compiles s2.first // Does not compile! Swift
  81. @skentphd Kotlin // Declarations var s1: String = "Hello, world!"

    var s2: String? = "Hello, world!" // Usage s1.first() // Compiles if (s2 != null) { s2!!.first() // Compiles } s2?.first() // Compiles // Declarations var s1: String = "Hello, world!" var s2: String? = "Hello, world!" // Usage s1.first // Compiles if s2 != nil { s2!.first // Compiles } s2?.first // Compiles Swift
  82. @skentphd Final Thoughts

  83. @skentphd Summary • Kotlin and Swift are fundamentally similar •

    Kotlin and Swift are functionally similar • Learning and developing with both is viable* *but not the only option!
  84. @skentphd Tactics • exercism.io language tracks • Official documentation •

    nilhcem.com/swift-is-like-kotlin/ • Spy on peer PRs • Contribute to peer projects
  85. @skentphd Thanks! Stuart Kent Detroit Labs @skentphd