Possible Futures with Kotlin

A presentation at GDG DevFest in September 2017 in Pittsburgh, PA, USA by Jake Wharton

Slide 1

Slide 1

Jake Wharton Possible Futures with Kotlin

Slide 2

Slide 2

Kotlin?

Slide 3

Slide 3

Slide 4

Slide 4

Slide 5

Slide 5

Slide 6

Slide 6

Slide 7

Slide 7

Slide 8

Slide 8

val firstName: String = "Jake" 
 val lastName: String? = null

Slide 9

Slide 9

val firstName: String = "Jake" 
 val lastName: String? = null

Slide 10

Slide 10

val firstName: String = "Jake" 
 val lastName: String? = null

Slide 11

Slide 11

val firstName: String = "Jake" 
 val lastName: String? = null

Slide 12

Slide 12

val firstName: String = "Jake" 
 val lastName: String? = null

Slide 13

Slide 13

val firstName = "Jake" 
 val lastName: String? = null

Slide 14

Slide 14

class User { 


public String getName() { 


// ... 


} 


public void setName(String name) { 


// ... 


} 
 }

// ^^^ Java

Slide 15

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 )

Slide 16

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

Slide 17

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

Slide 18

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

Slide 19

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

Slide 20

Slide 20

class User { 


var name

"Jake" 
 }

// ^^^ Kotlin

Slide 21

Slide 21

class User { 


var name

"Jake" 
 }

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

  • user.getName());

Slide 22

Slide 22

class User { 


var name

"Jake" 
 }

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

  • user.getName());

Slide 23

Slide 23

class User { 


var name

"Jake" 
 }

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

  • user.getName());

user.setName( "Jane" );

Slide 24

Slide 24

class User { 


var name

"Jake" 
 }

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

  • user.getName());

user.setName( "Jane" );

Slide 25

Slide 25

val user = User()

Slide 26

Slide 26

val user = User() 
 user = User()

Slide 27

Slide 27

val user = User() 
 user = User() 



 var currentUser = User() 
 currentUser = User()

Slide 28

Slide 28

fun Date.isTuesday(): Boolean { 


return day

2 
 }

Slide 29

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." ) 
 }

Slide 30

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." ) 
 }

Slide 31

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)

Slide 32

Slide 32

val executor = Executors.newSingleThreadExecutor(); 
 executor. execute { B println ( "Background thread!" ) } X

Slide 33

Slide 33

val executor = Executors.newSingleThreadExecutor();

val foo = Foo() 
 executor. execute (foo::printIt)

class Foo {

fun printIt() { B

println(

"Background thread!" ) } X

}

Slide 34

Slide 34

val executor = Executors.newSingleThreadExecutor();

val foo = Foo() 
 executor. execute (foo::printIt)

class Foo {

fun printIt() { B

println(

"Background thread!" ) } X

}

Slide 35

Slide 35

fun < T

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


// ... 
 }

Slide 36

Slide 36

fun < T

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


// ... 
 }

Slide 37

Slide 37

fun < T

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


// ... 
 } A

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

Slide 38

Slide 38

fun < T

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


// ... 
 } A

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

Slide 39

Slide 39

fun < T

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


// ... 
 } A

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

Slide 40

Slide 40

fun < T

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


// ... 
 } A

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

Slide 41

Slide 41

fun < T

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


// ... 
 } A

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

Slide 42

Slide 42

fun < T

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


// ... 
 } A

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

val oddSet = items. filterTo(mutableListOf()) { it % 2 != 0 }

Slide 43

Slide 43

fun < T

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


// ... 
 } A

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

Slide 44

Slide 44

inline fun < T

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


// ... 
 } A

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

Slide 45

Slide 45

inline fun < T

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

val destination = mutableListOf < T

()

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

Slide 46

Slide 46

inline fun < T

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

val destination = mutableListOf < T

()

for (item in this ) {

if (predicate(item)) destination.add(item) } B

return destination } A

val items = listOf ( 1 , 2 , 3 ) val destination = mutableListOf <Int>() for (item in items ) {

if (item % 2 != 0 ) destination.add(item) } G

val odds = destination

filter

it

Slide 47

Slide 47

class User { D 


val name

"Jake" 
 } A

Slide 48

Slide 48

class User(name: String) { D 


val name = name 
 } A 


    "

Jake"

Slide 49

Slide 49

class User( val

name : String) { 
 } A

Slide 50

Slide 50

class User( val

name : String)

Slide 51

Slide 51

class User( val

name : String)

val jake = User( "Jake" ) println ( "Hello, $ jake !" )

Slide 52

Slide 52

class User( val

name : String)

val jake = User( "Jake" ) println ( "Hello, $ jake !" )

Hello, User@3a71f4dd !

Slide 53

Slide 53

data class User( val

name : String)

val jake = User( "Jake" ) println ( "Hello, $ jake !" )

Hello, User@3a71f4dd !

Slide 54

Slide 54

@3a71f4dd data class User( val

name : String)

val jake = User( "Jake" ) println ( "Hello, $ jake !" )

Hello, User(name=Jake) !

Slide 55

Slide 55

data class User( val

name : String)

val jake = User( "Jake" ) println ( "Hello, $ jake !" )

Hello, User(name=Jake) !

Slide 56

Slide 56

class UserPersisence(db: SqlDatabase) {

private val deleteByName

= db.createStatement( "DELETE FROM user WHERE name = ?" )

fun delete(name: String) {

deleteByName .bind( 1 , name)

deleteByName .execute() } }

Slide 57

Slide 57

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

Slide 58

Slide 58

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

Slide 59

Slide 59

val deleteByName by lazy {

db.createStatement( "DELETE FROM user WHERE name = ?" ) } C

Slide 60

Slide 60

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 " ) }

Slide 61

Slide 61

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<String>()

Slide 62

Slide 62

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<String>() val nameView by bindView <TextView>(R. id . name )

Slide 63

Slide 63

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<String>() val nameView by bindView <TextView>(R. id . name )

Slide 64

Slide 64

fun main( vararg args: String) = runBlocking<Unit> {

val jobs = List ( 100_000 ) {

launch(CommonPool) {

delay( 1000L )

print ( "." )

} }

jobs.forEach { it.join() } }

Slide 65

Slide 65

X
O
X

X X O O O
X

Slide 66

Slide 66

iOS Web Server / API Android

Slide 67

Slide 67

Slide 68

Slide 68

package xo; public enum Mark {

X , O ; }

Slide 69

Slide 69

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 ); }

Slide 70

Slide 70

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(); }

@Override public String toString() {

Slide 71

Slide 71

package xo; public enum State {

PLAYER_1_MOVE ,

PLAYER_2_MOVE ,

PLAYER_1_WIN ,

PLAYER_2_WIN ,

DRAW , }

Slide 72

Slide 72

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 ) && player2 .equals(other. player2 )

Slide 73

Slide 73

Game Board Mark State Player

Slide 74

Slide 74

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

Slide 75

Slide 75

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

Slide 76

Slide 76

Game Mark State Board Player

Slide 77

Slide 77

State Board Game Mark Player

Slide 78

Slide 78

Game Mark State Board *.java *.kt Player

Slide 79

Slide 79

*.kt Game Mark State *.java

Slide 80

Slide 80

kotlinc *.kt Game Mark State *.java

Slide 81

Slide 81

*.kt Game Mark State *.java kotlinc

Slide 82

Slide 82

javac *.kt Game Mark State *.java kotlinc

Slide 83

Slide 83

javac *.kt Game Mark State *.java kotlinc

Slide 84

Slide 84

kotlinc javac *.kt Game Mark State *.java

Slide 85

Slide 85

kotlinc javac *.kt Game Mark State *.java

Slide 86

Slide 86

iOS Web Server / API Android

Slide 87

Slide 87

iOS Android Web Server / API

Slide 88

Slide 88

iOS Android View Models Web Server / API

Slide 89

Slide 89

iOS Android View Models Presenters Web Server / API

Slide 90

Slide 90

iOS Web Android View Models Presenters Server / API

Slide 91

Slide 91

iOS Web Android View Models Presenters Client Backend Server / API

Slide 92

Slide 92

iOS Web Server / API Android View Models Presenters Client Backend

Slide 93

Slide 93

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

Slide 94

Slide 94

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

Slide 95

Slide 95

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

Slide 96

Slide 96

data class NewGameUi Model(

val winTotal : Long,

val lossTotal : Long )

Slide 97

Slide 97

data class NewGameUi Model(

val winTotal : Long,

val lossTotal : Long )

data class GameUi Model(

val game : Game )

Slide 98

Slide 98

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

Slide 99

Slide 99

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

Slide 100

Slide 100

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

Slide 101

Slide 101

class NewGamePresenter { C

fun model(): NewGameUi Model { } B

} A

Slide 102

Slide 102

class NewGamePresenter( private val gameStore : GameStore) { C

fun model(): NewGameUi Model { } B

} A

Slide 103

Slide 103

class NewGamePresenter( private val gameStore : GameStore) { C

fun model(): NewGameUi Model {

val totals = gameStore .totals()

return NewGameUiModel(totals. wins , totals. losses ) } B

} A

Slide 104

Slide 104

class GamePresenter

{ D

fun model(): GameUiModel { C

} B

} A

Slide 105

Slide 105

class GamePresenter( private val gameId : Long) { D

fun model(): GameUiModel { C

} B

} A

Slide 106

Slide 106

class GamePresenter(

private val gameId : Long,

private val gameStore : GameStore ) { D

fun model(): GameUiModel { C

} B

} A

Slide 107

Slide 107

class GamePresenter(

private val gameId : Long,

private val gameStore : GameStore ) { D

fun models(): Observable<GameUiModel> { C

} B

} A

Slide 108

Slide 108

class GamePresenter(

private val gameId : Long,

private val gameStore : GameStore ) { D

fun move(row: Int, col: Int ) Z { C

} G

fun models(): Observable<GameUiModel> { C

} B

} A

Slide 109

Slide 109

class GamePresenter(

private val gameId : Long,

private val gameStore : GameStore ) { D

fun models(events: Observable<UiEvent>): Observable<GameUiModel> { C

} B

sealed class UiEvent {

data class Move( val

row : Int, val

col : Int): UiEvent() // ... }

} A fun move( ) Z { C } G

Slide 110

Slide 110

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

Slide 111

Slide 111

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

Slide 112

Slide 112

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

Slide 113

Slide 113

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

Slide 114

Slide 114

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

Slide 115

Slide 115

interface GameStore {

} A

Slide 116

Slide 116

interface GameStore {

fun totals(): Single<Totals>

data class Totals( val wins : Long, val losses : Long) } A

Slide 117

Slide 117

interface GameStore {

fun totals(): Single<Totals>

fun game(id: Long): Observable<Game>

data class Totals( val wins : Long, val losses : Long) } A

Slide 118

Slide 118

interface GameStore {

fun totals(): Single<Totals>

fun game(id: Long): Observable<Game>

fun move(id: Long, row: Int, col: Int): Completable

data class Totals( val wins : Long, val losses : Long) } A

Slide 119

Slide 119

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

Slide 120

Slide 120

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

Slide 121

Slide 121

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

Slide 122

Slide 122

class SqliteGameStore( private val

db : SQLiteDatabase) : GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

}

Slide 123

Slide 123

class IosGameStore( private val

db : CoreDataGameStore) : GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

}

Slide 124

Slide 124

class IosGameStore(

) : GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

}

private val

db : CoreDataGameStore

Slide 125

Slide 125

class IosGameStore(

) : GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

}

private val

db : CoreDataGameStore // tictactoe.def headers = game_store.h

Slide 126

Slide 126

class StorageGameStore( private val

store : Storage) : GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

} A

Slide 127

Slide 127

import org.w3c.dom.Storage class StorageGameStore(

    )

: GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

} A

              private val

store : Storage

Slide 128

Slide 128

Android iOS Web Client Backend iOS Web Server / API

Android View Models Presenters Business Logic Models

Slide 129

Slide 129

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

Slide 130

Slide 130

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

Slide 131

Slide 131

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

Slide 132

Slide 132

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 ()

}

Slide 133

Slide 133

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

Slide 134

Slide 134

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

Slide 135

Slide 135

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

Slide 136

Slide 136

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

Slide 137

Slide 137

class GameView(context: Context, attrs: AttributeSet)

: Consumer<GamePresenter.UiModel> {

fun accept(model: GamePresenter.UiModel) {

// TODO bind to view...

} }

Slide 138

Slide 138

iOS ???

Slide 139

Slide 139

function update(model) {

// TODO bind to DOM/template/JSX/whatever...

}

Slide 140

Slide 140

@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 udpated game ... }

Slide 141

Slide 141

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

Slide 142

Slide 142

X
O
X

X X O O O
X

Slide 143

Slide 143

twitter.com/ github.com/ .com Possible Futures with Kotlin

jakewharton jakewharton jakewharton