$30 off During Our Annual Pro Sale. View Details »

Kotlin: Write Once, Run Actually Everywhere (QCon SF 2018)

Kotlin: Write Once, Run Actually Everywhere (QCon SF 2018)

Kotlin used to be described as a new language for the JVM which aims to fix some of the pain points of Java. But more recently Kotlin is also a language for the web, iOS, desktop, embedded, and just about anywhere else code can run. JetBrains, the creators of Kotlin, have placed a strong emphasis on targeting multiple platforms in how the language is compiled, its language features, and the standard libraries. This talk will be an exploration of the Kotlin language, how it compiles to run on more than just the JVM, and whether it can fully pull off the multiplatform trick allowing a single codebase to run everywhere.

Video: coming soon

Jake Wharton
PRO

November 06, 2018
Tweet

More Decks by Jake Wharton

Other Decks in Programming

Transcript

  1. Jake Wharton
    Kotlin: Write Once,
    Run Everywhere
    Actually

    View Slide

  2. Kotlin?

    View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. val firstName: String = "Jake"

    val lastName: String? = null

    View Slide

  9. val firstName: String = "Jake"

    val lastName: String? = null

    View Slide

  10. val firstName: String = "Jake"

    val lastName: String? = null

    View Slide

  11. val firstName: String = "Jake"

    val lastName: String? = null

    View Slide

  12. val firstName: String = "Jake"

    val lastName: String? = null

    View Slide

  13. val firstName = "Jake"

    val lastName: String? = null

    View Slide

  14. class User {

    public String getName() {

    // ...

    }

    public void setName(String name) {

    // ...

    }

    }
    // ^^^ Java

    View Slide

  15. class User {

    public String getName() {

    // ...

    }X

    public void setName(String name) {

    // ...

    }Y

    }Z
    // ^^^ Java vvv Kotlin
    val user = User()

    println("Name is " + user.name)

    View Slide

  16. class User {

    public String getName() {

    // ...

    }X

    public void setName(String name) {

    // ...

    }Y

    }Z
    // ^^^ Java vvv Kotlin
    val user = User()

    println("Name is " + user.name)X

    View Slide

  17. class User {

    public String getName() {

    // ...

    }X

    public void setName(String name) {

    // ...

    }Y

    }Z
    // ^^^ Java vvv Kotlin
    val user = User()

    println("Name is ${user.name}")X

    View Slide

  18. class User {

    public String getName() {

    // ...

    }X

    public void setName(String name) {

    // ...

    }Y

    }Z
    // ^^^ Java vvv Kotlin
    val user = User()

    println("Name is $user")X

    View Slide

  19. class User {

    public String getName() {

    // ...

    }X

    public void setName(String name) {

    // ...

    }Y

    }Z
    // ^^^ Java vvv Kotlin
    val user = User()

    println("Name is $user")X

    View Slide

  20. class User {

    var name = "Jake"

    }
    // ^^^ Kotlin

    View Slide

  21. class User {

    var name = "Jake"

    }
    // ^^^ Kotlin vvv Java
    User user = new User();
    System.out.println("Name is " + user.getName());

    View Slide

  22. class User {

    var name = "Jake"

    }
    // ^^^ Kotlin vvv Java
    User user = new User();
    System.out.println("Name is " + user.getName());

    View Slide

  23. class User {

    var name = "Jake"

    }
    // ^^^ Kotlin vvv Java
    User user = new User();
    System.out.println("Name is " + user.getName());
    user.setName("Jane");

    View Slide

  24. class User {

    var name = "Jake"

    }
    // ^^^ Kotlin vvv Java
    User user = new User();
    System.out.println("Name is " + user.getName());
    user.setName("Jane");

    View Slide

  25. val user = User()

    View Slide

  26. val user = User()

    user = User()

    View Slide

  27. val user = User()

    user = User()


    var currentUser = User()

    currentUser = User()

    View Slide

  28. fun Date.isTuesday(): Boolean {

    return day == 2

    }

    View Slide

  29. fun Date.isTuesday(): Boolean {

    return day == 2

    }
    val epoch = Date(1970, 0, 0)

    if (epoch.isTuesday()) {

    println("The epoch was a Tuesday.")

    } else {

    println("The epoch was not a Tuesday.")

    }

    View Slide

  30. fun Date.isTuesday(): Boolean {

    return day == 2

    }
    val epoch = Date(1970, 0, 0)

    if (epoch.isTuesday()) {

    println("The epoch was a Tuesday.")

    } else {

    println("The epoch was not a Tuesday.")

    }

    View Slide

  31. fun Date.isTuesday(): Boolean {

    return day == 2

    }
    val epoch = Date(1970, 0, 0)

    if (epoch.isTuesday()) {

    println("The epoch was a Tuesday.")

    } else {

    println("The epoch was not a Tuesday.")

    }
    // ^^^ Kotlin vvv Java
    DateKt.isTuesday(date)

    View Slide

  32. val executor = Executors.newSingleThreadExecutor();

    executor.execute {Bprintln("Background thread!") }X

    View Slide

  33. val executor = Executors.newSingleThreadExecutor();
    val foo = Foo()

    executor.execute(foo::printIt)
    class Foo {
    fun printIt() {B
    println("Background thread!")
    }X
    }

    View Slide

  34. val executor = Executors.newSingleThreadExecutor();
    val foo = Foo()

    executor.execute(foo::printIt)
    class Foo {
    fun printIt() {B
    println("Background thread!")
    }X
    }

    View Slide

  35. fun List.filter(predicate: (T) -> Boolean): List {

    // ...

    }

    View Slide

  36. fun List.filter(predicate: (T) -> Boolean): List {

    // ...

    }

    View Slide

  37. fun List.filter(predicate: (T) -> Boolean): List {

    // ...

    }A
    val items = listOf(1, 2, 3)
    val odds = items.filter({ item -> item % 2 != 0 })B

    View Slide

  38. fun List.filter(predicate: (T) -> Boolean): List {

    // ...

    }A
    val items = listOf(1, 2, 3)
    val odds = items.filter({ item -> item % 2 != 0 })B

    View Slide

  39. fun List.filter(predicate: (T) -> Boolean): List {

    // ...

    }A
    val items = listOf(1, 2, 3)
    val odds = items.filter({ it % 2 != 0 })B

    View Slide

  40. fun List.filter(predicate: (T) -> Boolean): List {

    // ...

    }A
    val items = listOf(1, 2, 3)
    val odds = items.filter()B{ it % 2 != 0 }

    View Slide

  41. fun List.filter(predicate: (T) -> Boolean): List {

    // ...

    }A
    val items = listOf(1, 2, 3)
    val odds = items.filter { it % 2 != 0 }

    View Slide



  42. val odds
    fun List.filter(predicate: (T) -> Boolean): List {

    // ...

    }A
    val items = listOf(1, 2, 3)
    List = items.filter { it % 2 != 0 }
    val oddSet = items.filterTo(mutableListOf()) { it % 2 != 0 }

    View Slide

  43. fun List.filter(predicate: (T) -> Boolean): List {

    // ...

    }A
    val items = listOf(1, 2, 3)
    val odds = items.filter { it % 2 != 0 }

    View Slide

  44. inline fun List.filter(predicate: (T) -> Boolean): List {

    // ...

    }A
    val items = listOf(1, 2, 3)
    val odds = items.filter { it % 2 != 0 }

    View Slide

  45. inline fun List.filter(predicate: (T) -> Boolean): List {
    val destination = mutableListOf()
    for (item in this) {
    if (predicate(item)) destination.add(item)
    }B
    return destination
    }A
    val items = listOf(1, 2, 3)
    val odds = items.filter { it % 2 != 0 }
    val destination = mutableListOf< >()
    for (item in ) {
    if ( item ) destination.add(item)
    }G
    destination

    View Slide

  46. inline fun List.filter(predicate: (T) -> Boolean): List {
    val destination = mutableListOf()
    for (item in this) {
    if (predicate(item)) destination.add(item)
    }B
    return destination
    }A
    val items = listOf(1, 2, 3)
    val destination = mutableListOf()
    for (item in items) {
    if (item % 2 != 0) destination.add(item)
    }G
    val odds = destination
    filter it

    View Slide

  47. class User {D

    val name = "Jake"

    }A

    View Slide

  48. class User(name: String) {D

    val name = name

    }A

    "Jake"

    View Slide

  49. class User(val name: String) {

    }A

    View Slide

  50. class User(val name: String)

    View Slide

  51. class User(val name: String)
    val jake = User("Jake")
    println("Hello, $jake!")

    View Slide

  52. class User(val name: String)
    val jake = User("Jake")
    println("Hello, $jake!")
    Hello, User@3a71f4dd!

    View Slide

  53. data class User(val name: String)
    val jake = User("Jake")
    println("Hello, $jake!")
    Hello, User@3a71f4dd!

    View Slide

  54. @3a71f4dd
    data class User(val name: String)
    val jake = User("Jake")
    println("Hello, $jake!")
    Hello, User(name=Jake)!

    View Slide

  55. data class User(val name: String)
    val jake = User("Jake")
    println("Hello, $jake!")
    Hello, User(name=Jake)!

    View Slide

  56. data class User(val name: String, val age: Int)
    val jake = User("Jake")
    println("Hello, $jake!")
    Hello, User(name=Jake)!

    View Slide

  57. data class User(val name: String, val age: Int)
    val jake = User("Jake", 4)

    View Slide

  58. data class User(val name: String, val age: Int)
    val jake = User("Jake", 4)
    val (name, age) = jake

    View Slide

  59. data class User(val name: String, val age: Int)
    val (name, age) = User("Jake", 4)

    View Slide

  60. data class User(val name: String, val age: Int)
    fun dbLookup() = User("Jake", 4)
    val (name, age) = dbLookup()

    View Slide

  61. class UserPersisence(db: SqlDatabase) {
    private val deleteByName
    = db.createStatement("DELETE FROM user WHERE name = ?")
    fun delete(name: String) {
    deleteByName.bind(1, name)
    deleteByName.execute()
    }
    }

    View Slide

  62. class UserPersisence(db: SqlDatabase) {
    private val deleteByName
    = db.createStatement("DELETE FROM user WHERE name = ?")
    fun delete(name: String) {
    deleteByName.bind(1, name)
    deleteByName.execute()
    }B
    }A

    View Slide

  63. class UserPersisence(db: SqlDatabase) {
    private val deleteByName by lazy {
    db.createStatement("DELETE FROM user WHERE name = ?")
    }C
    fun delete(name: String) {
    deleteByName.bind(1, name)
    deleteByName.execute()
    }B
    }A

    View Slide

  64. val deleteByName by lazy {
    db.createStatement("DELETE FROM user WHERE name = ?")
    }C

    View Slide

  65. val deleteByName by lazy {
    db.createStatement("DELETE FROM user WHERE name = ?")
    }C
    var name by Delegates.observable("Jane") { prop, old, new ->
    println("Name changed from $old to $new")
    }

    View Slide

  66. val deleteByName by lazy {
    db.createStatement("DELETE FROM user WHERE name = ?")
    }C
    var name by Delegates.observable("Jane") { prop, old, new ->
    println("Name changed from $old to $new")
    }
    var address by Delegates.notNull()

    View Slide

  67. val deleteByName by lazy {
    db.createStatement("DELETE FROM user WHERE name = ?")
    }C
    var name by Delegates.observable("Jane") { prop, old, new ->
    println("Name changed from $old to $new")
    }
    var address by Delegates.notNull()
    val nameView by bindView(R.id.name)

    View Slide

  68. val deleteByName by lazy {
    db.createStatement("DELETE FROM user WHERE name = ?")
    }C
    var name by Delegates.observable("Jane") { prop, old, new ->
    println("Name changed from $old to $new")
    }
    var address by Delegates.notNull()
    val nameView by bindView(R.id.name)

    View Slide

  69. fun main(vararg args: String) = runBlocking {
    val jobs = List(100_000) {
    launch(CommonPool) {
    delay(1000L)
    print(".")
    }
    }
    jobs.forEach { it.join() }
    }

    View Slide

  70. View Slide

  71. View Slide

  72. View Slide

  73. Multiplatform Abstraction Your App

    View Slide

  74. Your App

    View Slide

  75. Your App

    View Slide

  76. X O X
    X X O
    O O X

    View Slide

  77. iOS Web Server / API
    Android

    View Slide

  78. Android

    View Slide

  79. package xo;
    public enum Mark {
    X, O;
    }

    View Slide

  80. package xo;
    import java.util.Arrays;
    public final class Board {
    private static final int SIZE = 3;
    private final Mark[][] cells;
    public Board() {
    this.cells = new Mark[3][3];
    }
    // TODO mutator methods...
    @Override public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Board)) return false;
    Board other = (Board) o;
    return Arrays.deepEquals(cells, other.cells);
    }
    @Override public int hashCode() {
    return Arrays.deepHashCode(cells);

    View Slide

  81. package xo;
    import static java.util.Objects.requireNonNull;
    public final class Player {
    public final String name;
    public final Mark mark;
    public Player(String name, Mark mark) {
    this.name = requireNonNull(name, "name == null");
    this.mark = requireNonNull(mark, "mark == null");
    }
    @Override public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Player)) return false;
    Player other = (Player) o;
    return name.equals(other.name) && mark == other.mark;
    }
    @Override public int hashCode() {
    return 31 * name.hashCode() + mark.hashCode();
    }

    View Slide

  82. package xo;
    public enum State {
    PLAYER_1_MOVE,
    PLAYER_2_MOVE,
    PLAYER_1_WIN,
    PLAYER_2_WIN,
    DRAW,
    }

    View Slide

  83. package xo;
    import static java.util.Objects.requireNonNull;
    public final class Game {
    private final Board board;
    private final Player player1;
    private final Player player2;
    private State state = State.PLAYER_1_MOVE;
    public Game(Board board, Player player1, Player player2) {
    this.board = requireNonNull(board, "board == null");
    this.player1 = requireNonNull(player1, "player1 == null");
    this.player2 = requireNonNull(player2, "player2 == null");
    }
    // TODO mutator methods...
    @Override public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Game)) return false;
    Game other = (Game) o;
    return board.equals(other.board)
    && player1.equals(other.player1)

    View Slide

  84. Game Board Mark
    State
    Player

    View Slide

  85. Game Board Mark
    State
    Player

    View Slide

  86. public final class Player {
    public final String name;
    public final Mark mark;
    public Player(String name, Mark mark) {
    this.name = requireNonNull(name, "name == null");
    this.mark = requireNonNull(mark, "mark == null");
    }A
    @Override public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Player)) return false;
    Player other = (Player) o;
    return name.equals(other.name) && mark == other.mark;
    }B
    @Override public int hashCode() {
    return 31 * name.hashCode() + mark.hashCode();
    }C
    @Override public String toString() {
    return "Player{name='" + name + ", mark=" + mark + '}';
    }D
    }E

    View Slide

  87. data class Player(val name: String, val mark: Mark)
    public final {
    public final ;
    public final ;
    public Player(String name, Mark mark) {
    this.name = requireNonNull(name, "name == null");
    this.mark = requireNonNull(mark, "mark == null");
    }A
    @Override public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Player)) return false;
    Player other = (Player) o;
    return name.equals(other.name) && mark == other.mark;
    }B
    @Override public int hashCode() {
    return 31 * name.hashCode() + mark.hashCode();
    }C
    @Override public String toString() {
    return "Player{name='" + name + ", mark=" + mark + '}';
    }D
    }E

    View Slide

  88. Game Mark
    State
    Board
    Player

    View Slide

  89. State
    Board
    Game Mark
    Player

    View Slide

  90. Game Mark
    State
    Board
    *.java
    *.kt
    Player

    View Slide

  91. *.kt
    Game
    Mark
    State
    *.java

    View Slide

  92. kotlinc
    *.kt
    Game
    Mark
    State
    *.java

    View Slide

  93. *.kt
    Game
    Mark
    State
    *.java
    kotlinc

    View Slide

  94. javac
    *.kt
    Game
    Mark
    State
    *.java
    kotlinc

    View Slide

  95. kotlinc javac
    *.kt
    Game
    Mark
    State
    *.java

    View Slide

  96. kotlinc javac
    *.kt
    Game
    Mark
    State
    *.java

    View Slide

  97. kotlin-stdlib
    kotlinc javac
    *.kt
    Game
    Mark
    State
    *.java

    View Slide

  98. kotlin-stdlib
    kotlinc javac
    *.kt
    Game
    Mark
    State
    *.java
    models/

    View Slide

  99. iOS Web Server / API
    Android

    View Slide

  100. iOS Web Server / API
    Android

    View Slide

  101. iOS
    Web Server / API
    Android
    View Models

    View Slide

  102. iOS
    Web Server / API
    Android
    View Models
    Presenters

    View Slide

  103. iOS
    Web Server / API
    Android
    View Models
    Presenters

    View Slide

  104. iOS
    Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend

    View Slide

  105. iOS
    Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend

    View Slide

  106. iOS
    Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic

    View Slide

  107. iOS
    Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  108. iOS
    Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  109. data class NewGameUiModel(
    val winTotal: Long,
    val lossTotal: Long
    )

    View Slide

  110. data class NewGameUiModel(
    val winTotal: Long,
    val lossTotal: Long
    )
    data class GameUiModel(
    val game: Game
    )

    View Slide

  111. data class NewGameUiModel(
    val winTotal: Long,
    val lossTotal: Long
    )
    data class GameUiModel(
    )
    val game: Game

    View Slide

  112. data class NewGameUiModel(
    val winTotal: Long,
    val lossTotal: Long
    )
    data class GameUiModel(
    val game: Game
    )

    View Slide

  113. iOS
    Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  114. iOS
    Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  115. iOS
    Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  116. class NewGamePresenter {C
    fun model(): NewGameUiModel {
    }B
    }A

    View Slide

  117. class NewGamePresenter(private val gameStore: GameStore) {C
    fun model(): NewGameUiModel {
    }B
    }A

    View Slide

  118. class NewGamePresenter(private val gameStore: GameStore) {C
    fun model(): NewGameUiModel {
    val totals = gameStore.totals()
    return NewGameUiModel(totals.wins, totals.losses)
    }B
    }A

    View Slide

  119. class GamePresenter {D
    fun model(): GameUiModel {C
    }B
    }A

    View Slide

  120. class GamePresenter(private val gameId: Long) {D
    fun model(): GameUiModel {C
    }B
    }A

    View Slide

  121. class GamePresenter(
    private val gameId: Long,
    private val gameStore: GameStore
    ) {D
    fun model(): GameUiModel {C
    }B
    }A

    View Slide

  122. class GamePresenter(
    private val gameId: Long,
    private val gameStore: GameStore
    ) {D
    fun models(): Observable {C
    }B
    }A

    View Slide

  123. class GamePresenter(
    private val gameId: Long,
    private val gameStore: GameStore
    ) {D
    fun move(row: Int, col: Int )Z{C
    }G
    fun models(): Observable {C
    }B
    }A

    View Slide

  124. class GamePresenter(
    private val gameId: Long,
    private val gameStore: GameStore
    ) {D
    fun models(events: Observable): Observable {C
    }B
    sealed class UiEvent {
    data class Move(val row: Int, val col: Int): UiEvent()
    // ...
    }
    }A
    fun move( )Z{C
    }G

    View Slide

  125. iOS
    Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  126. iOS
    Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  127. iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  128. iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  129. interface GameStore {
    }A

    View Slide

  130. interface GameStore {
    suspend fun totals(): Totals
    data class Totals(val wins: Long, val losses: Long)
    }A

    View Slide

  131. interface GameStore {
    suspend fun totals(): Totals
    fun game(id: Long): Observable
    data class Totals(val wins: Long, val losses: Long)
    }A

    View Slide

  132. interface GameStore {
    suspend fun totals(): Totals
    fun game(id: Long): Observable
    suspend fun move(id: Long, row: Int, col: Int)
    data class Totals(val wins: Long, val losses: Long)
    }A

    View Slide

  133. iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  134. iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  135. Android iOS Web
    iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  136. class SqliteGameStore(private val db: SQLiteDatabase) : GameStore {
    override suspend fun totals() = TODO()
    override fun game(id: Long) = TODO()
    override suspend fun move(id: Long, row: Int, col: Int) = TODO()
    }

    View Slide

  137. class IosGameStore(private val db: CoreDataGameStore) : GameStore {
    override suspend fun totals() = TODO()
    override fun game(id: Long) = TODO()
    override suspend fun move(id: Long, row: Int, col: Int) = TODO()
    }

    View Slide

  138. class IosGameStore( ) : GameStore {
    override suspend fun totals() = TODO()
    override fun game(id: Long) = TODO()
    override suspend fun move(id: Long, row: Int, col: Int) = TODO()
    }
    private val db: CoreDataGameStore

    View Slide

  139. class IosGameStore( ) : GameStore {
    override suspend fun totals() = TODO()
    override fun game(id: Long) = TODO()
    override suspend fun move(id: Long, row: Int, col: Int) = TODO()
    }
    private val db: CoreDataGameStore
    // tictactoe.def
    headers = game_store.h

    View Slide

  140. class StorageGameStore(private val store: Storage) : GameStore {
    override suspend fun totals() = TODO()
    override fun game(id: Long) = TODO()
    override suspend fun move(id: Long, row: Int, col: Int) = TODO()
    }A

    View Slide

  141. import org.w3c.dom.Storage
    class StorageGameStore( ) : GameStore {
    override suspend fun totals() = TODO()
    override fun game(id: Long) = TODO()
    override suspend fun move(id: Long, row: Int, col: Int) = TODO()
    }A
    private val store: Storage

    View Slide

  142. Android iOS Web
    iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  143. Android iOS Web
    iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  144. Android iOS Web
    iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  145. Android iOS Web
    iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  146. object TicTacToeLogic {
    fun validateMove(
    game: Game, player: Player, row: Int, col: Int): Boolean {
    when (game.state) {
    State.PLAYER_1_MOVE -> require(game.player1 == player)
    State.PLAYER_2_MOVE -> require(game.player2 == player)
    else -> error("Game is over")
    }
    return game.board[row][col] == null
    }
    fun nextState(game: Game): State {
    findWinner(game.board)?.let {
    return if (game.player1.mark == it) State.PLAYER_1_WIN
    else State.PLAYER_2_WIN
    }
    if (game.board.isComplete()) {
    return State.DRAW
    }
    return if (game.state == State.PLAYER_1_MOVE) State.PLAYER_2_MOVE
    else State.PLAYER_1_MOVE
    }
    fun findWinner(board: Board): Mark? = TODO()
    fun Board.isComplete(): Boolean = TODO()
    }

    View Slide

  147. Android iOS Web
    iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  148. Android iOS Web
    iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  149. Android iOS Web
    iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  150. Android iOS Web
    iOS Web
    Server / API
    Android
    View Models
    Presenters
    Client Backend
    Business Logic
    Models

    View Slide

  151. class GameView(context: Context, attrs: AttributeSet)
    : ContraintLayout(context, attrs),
    Consumer {
    override fun accept(model: GamePresenter.UiModel) {
    // TODO bind to view...
    }
    }

    View Slide

  152. class GameViewController : UiViewController {
    func update(model: GamePresenter.UiModel) {
    // TODO bind to view...
    }
    }

    View Slide

  153. function update(model) {
    // TODO bind to DOM/template/JSX/whatever...
    }

    View Slide

  154. @POST @Path("/api/move")
    fun Game move(
    @QueryParam("id") id: Long,
    @QueryParam("row") row: Int,
    @QueryParam("col") col: Int) {
    // TODO check business logic, persist, return updated game ...
    }

    View Slide

  155. View Slide

  156. apk via aab
    apk
    via
    aab
    apk
    webapk
    apk via aab
    via url
    url
    apk via aab
    via url
    Chrome app
    url
    url
    pwa
    ipa
    ipa
    url
    url

    View Slide

  157. View Slide

  158. View Slide

  159. kotlin-stdlib
    kotlinc javac
    *.kt
    *.java

    View Slide

  160. View Slide

  161. View Slide

  162. external interface ChromePlatform {
    val omnibox: Omnibox
    val storage: Storage
    val tabs: Tabs
    }A
    @JsName("chrome")
    external val Chrome: ChromePlatform

    View Slide

  163. $ ts2kt chrome.ts
    external interface ChromePlatform {
    val omnibox: Omnibox
    val storage: Storage
    val tabs: Tabs
    }A
    @JsName("chrome")
    external val Chrome: ChromePlatform

    View Slide

  164. external interface ChromePlatform {
    val omnibox: Omnibox
    val storage: Storage
    val tabs: Tabs
    }A
    @JsName("chrome")
    external val Chrome: ChromePlatform

    View Slide

  165. external interface ChromePlatform {
    val omnibox: Omnibox
    val storage: Storage
    val tabs: Tabs
    }A
    @JsName("chrome")
    external val Chrome: ChromePlatform
    fun main(vararg args: String) {
    val configStore = StorageAreaConfigStore(
    Chrome.storage.sync, PRODUCTION_GIT_WEB, PRODUCTION_DAC)
    // ...
    }

    View Slide

  166. function main(args) {
    var configStore = new StorageAreaConfigStore(chrome.storage.sync,
    reference.PRODUCTION_GIT_WEB, reference.PRODUCTION_DAC);
    // ...
    }

    View Slide

  167. View Slide

  168. View Slide

  169. class IosGameStore(private val db: CoreDataGameStore) : GameStore {
    override suspend fun totals() = TODO()
    override fun game(id: Long) = TODO()
    override suspend fun move(id: Long, row: Int, col: Int) = TODO()
    }

    View Slide

  170. class IosGameStore(private val db: CoreDataGameStore) : GameStore {
    override suspend fun totals() = TODO()
    override fun game(id: Long) = TODO()
    override suspend fun move(id: Long, row: Int, col: Int) = TODO()
    }

    View Slide

  171. class IosGameStore(private val db: CoreDataGameStore) : GameStore {
    override suspend fun totals() = TODO()
    override fun game(id: Long) = TODO()
    override suspend fun move(id: Long, row: Int, col: Int) = TODO()
    }
    // tictactoe.def
    headers = game_store.h

    View Slide

  172. class IosGameStore(private val db: CoreDataGameStore) : GameStore {
    override suspend fun totals() = TODO()
    override fun game(id: Long) = TODO()
    override suspend fun move(id: Long, row: Int, col: Int) = TODO()
    }A
    // tictactoe.def
    headers = game_store.h
    package = gamestore

    View Slide

  173. import gamestore.CoreDataGameStore
    class IosGameStore(private val db: CoreDataGameStore) : GameStore {
    override suspend fun totals() = TODO()
    override fun game(id: Long) = TODO()
    override suspend fun move(id: Long, row: Int, col: Int) = TODO()
    }A
    // tictactoe.def
    headers = game_store.h
    package = gamestore

    View Slide

  174. konan
    *.kt

    View Slide

  175. konan
    *.kt
    *.h

    View Slide

  176. konan
    *.kt
    llvm
    *.h

    View Slide

  177. konan
    *.kt
    llvm
    *.h

    View Slide

  178. konan
    *.kt
    llvm
    *.h

    View Slide

  179. View Slide

  180. View Slide

  181. import kotlin.collections.ArrayList
    import kotlin.collections.MutableList
    val users: MutableList = ArrayList()

    View Slide

  182. import java.util.concurrent.CopyOnWriteList
    import kotlin.collections.MutableList
    val users: MutableList = CopyOnWriteArrayList()
    kotlin.collections.ArrayList

    View Slide

  183. import kotlin.collections.MutableList
    val users: MutableList = CopyOnWriteArrayList()

    View Slide

  184. import kotlin.collections.MutableList
    val users: MutableList = CopyOnWriteArrayList()
    expect class CopyOnWriteArrayList : MutableList

    View Slide

  185. import kotlin.collections.MutableList
    val users: MutableList = CopyOnWriteArrayList()
    expect class CopyOnWriteArrayList : MutableList
    actual typealias CopyOnWriteArrayList =
    java.util.concurrent.CopyOnWriteArrayList

    View Slide

  186. import kotlin.collections.MutableList
    val users: MutableList = CopyOnWriteArrayList()
    expect class CopyOnWriteArrayList : MutableList
    actual typealias CopyOnWriteArrayList =
    java.util.concurrent.CopyOnWriteArrayList
    actual typealias CopyOnWriteArrayList = ArrayList

    View Slide

  187. import kotlin.collections.MutableList
    val users: MutableList = CopyOnWriteArrayList()
    expect class CopyOnWriteArrayList : MutableList
    actual typealias CopyOnWriteArrayList =
    java.util.concurrent.CopyOnWriteArrayList
    actual typealias CopyOnWriteArrayList = ArrayList
    actual class CopyOnWriteArrayList : MutableList {
    // it's complicated...
    }

    View Slide

  188. expect interface Closeable {
    fun close()
    }

    View Slide

  189. expect interface Closeable {
    fun close()
    }
    actual typealias Closeable = java.io.Closeable
    actual interface Closeable {
    actual fun close()
    }
    actual interface Closeable {
    actual fun close()
    }

    View Slide

  190. View Slide

  191. View Slide

  192. SDK Search

    View Slide

  193. View Slide

  194. View Slide

  195. View Slide

  196. View Slide

  197. @JakeWharton
    Kotlin: Write Once,
    Run Everywhere
    Actually

    View Slide