A presentation at GDG DevFest in in Pittsburgh, PA, USA by Jake Wharton
Jake Wharton Possible Futures with Kotlin
Kotlin?
val firstName: String = "Jake" val lastName: String? = null
val firstName: String = "Jake" val lastName: String? = null
val firstName: String = "Jake" val lastName: String? = null
val firstName: String = "Jake" val lastName: String? = null
val firstName: String = "Jake" val lastName: String? = null
val firstName = "Jake" val lastName: String? = null
class User {
public String getName() {
// ...
}
public void setName(String name) {
// ...
} }
// ^^^ Java
class User {
public String getName() {
// ...
} X
public void setName(String name) {
// ...
} Y } Z
// ^^^ Java vvv Kotlin
val user = User() println ( "Name is "
class User {
public String getName() {
// ...
} X
public void setName(String name) {
// ...
} Y } Z
// ^^^ Java vvv Kotlin
val user = User() println ( "Name is "
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
class User {
public String getName() {
// ...
} X
public void setName(String name) {
// ...
} Y } Z
// ^^^ Java vvv Kotlin
val user = User() println ( "Name is $ user " ) X
class User {
public String getName() {
// ...
} X
public void setName(String name) {
// ...
} Y } Z
// ^^^ Java vvv Kotlin
val user = User() println ( "Name is $ user " ) X
class User {
"Jake" }
// ^^^ Kotlin
class User {
"Jake" }
// ^^^ Kotlin vvv Java User user = new User(); System. out .println( "Name is "
class User {
"Jake" }
// ^^^ Kotlin vvv Java User user = new User(); System. out .println( "Name is "
class User {
"Jake" }
// ^^^ Kotlin vvv Java User user = new User(); System. out .println( "Name is "
user.setName( "Jane" );
class User {
"Jake" }
// ^^^ Kotlin vvv Java User user = new User(); System. out .println( "Name is "
user.setName( "Jane" );
val user = User()
val user = User() user = User()
val user = User() user = User()
var currentUser = User() currentUser = User()
fun Date.isTuesday(): Boolean {
2 }
fun Date.isTuesday(): Boolean {
2 }
val epoch = Date( 1970 , 0 , 0 ) if (epoch. isTuesday ()) {
println ( "The epoch was a Tuesday." ) } else {
println ( "The epoch was not a Tuesday." ) }
fun Date.isTuesday(): Boolean {
2 }
val epoch = Date( 1970 , 0 , 0 ) if (epoch. isTuesday ()) {
println ( "The epoch was a Tuesday." ) } else {
println ( "The epoch was not a Tuesday." ) }
fun Date.isTuesday(): Boolean {
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)
val executor = Executors.newSingleThreadExecutor(); executor. execute { B println ( "Background thread!" ) } X
val executor = Executors.newSingleThreadExecutor();
val foo = Foo() executor. execute (foo::printIt)
class Foo {
fun printIt() { B
println(
"Background thread!" ) } X
}
val executor = Executors.newSingleThreadExecutor();
val foo = Foo() executor. execute (foo::printIt)
class Foo {
fun printIt() { B
println(
"Background thread!" ) } X
}
fun < T
List< T .filter(predicate: ( T ) -> Boolean): List< T {
// ... }
fun < T
List< T .filter(predicate: ( T ) -> Boolean): List< T {
// ... }
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
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
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
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 }
fun < T
List< T .filter(predicate: ( T ) -> Boolean): List< T {
// ... } A
val items = listOf ( 1 , 2 , 3 ) val odds = items. filter { it % 2 != 0 }
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 }
fun < T
List< T .filter(predicate: ( T ) -> Boolean): List< T {
// ... } A
val items = listOf ( 1 , 2 , 3 ) val odds = items. filter { it % 2 != 0 }
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 }
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
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
class User { D
"Jake" } A
class User(name: String) { D
val name = name } A
"
Jake"
class User( val
name : String) { } A
class User( val
name : String)
class User( val
name : String)
val jake = User( "Jake" ) println ( "Hello, $ jake !" )
class User( val
name : String)
val jake = User( "Jake" ) println ( "Hello, $ jake !" )
Hello, User@3a71f4dd !
data class User( val
name : String)
val jake = User( "Jake" ) println ( "Hello, $ jake !" )
Hello, User@3a71f4dd !
@3a71f4dd data class User( val
name : String)
val jake = User( "Jake" ) println ( "Hello, $ jake !" )
Hello, User(name=Jake) !
data class User( val
name : String)
val jake = User( "Jake" ) println ( "Hello, $ jake !" )
Hello, User(name=Jake) !
class UserPersisence(db: SqlDatabase) {
private val deleteByName
= db.createStatement( "DELETE FROM user WHERE name = ?" )
fun delete(name: String) {
deleteByName .bind( 1 , name)
deleteByName .execute() } }
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
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
val deleteByName by lazy {
db.createStatement( "DELETE FROM user WHERE name = ?" ) } C
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 " ) }
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 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 )
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 )
fun main( vararg args: String) = runBlocking<Unit> {
val jobs = List ( 100_000 ) {
launch(CommonPool) {
delay( 1000L )
print ( "." )
} }
jobs.forEach { it.join() } }
X
O
X
X X
O
O O
X
iOS Web Server / API Android
package xo; public enum Mark {
X , O ; }
package xo; import java.util.Arrays; public final class Board {
3 ;
private final Mark[][] cells ;
public Board() {
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 ); }
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) {
requireNonNull (name, "name == null" );
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() {
package xo; public enum State {
PLAYER_1_MOVE ,
PLAYER_2_MOVE ,
PLAYER_1_WIN ,
PLAYER_2_WIN ,
DRAW , }
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) {
requireNonNull (board, "board == null" );
requireNonNull (player1, "player1 == null" );
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 )
Game Board Mark State Player
public final class Player {
public final String name ;
public final Mark mark ;
public Player(String name, Mark mark) {
requireNonNull (name, "name == null" );
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
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
Game Mark State Board Player
State Board Game Mark Player
Game Mark State Board *.java *.kt Player
*.kt Game Mark State *.java
kotlinc *.kt Game Mark State *.java
*.kt Game Mark State *.java kotlinc
javac *.kt Game Mark State *.java kotlinc
javac *.kt Game Mark State *.java kotlinc
kotlinc javac *.kt Game Mark State *.java
kotlinc javac *.kt Game Mark State *.java
iOS Web Server / API Android
iOS Android Web Server / API
iOS Android View Models Web Server / API
iOS Android View Models Presenters Web Server / API
iOS Web Android View Models Presenters Server / API
iOS Web Android View Models Presenters Client Backend Server / API
iOS Web Server / API Android View Models Presenters Client Backend
iOS Web Server / API Android View Models Presenters Client Backend Business Logic
iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models
iOS Android View Models Web Server / API Presenters Client Backend Business Logic Models
data class NewGameUi Model(
val winTotal : Long,
val lossTotal : Long )
data class NewGameUi Model(
val winTotal : Long,
val lossTotal : Long )
data class GameUi Model(
val game : Game )
iOS Android View Models Web Server / API Presenters Client Backend Business Logic Models
iOS Android View Models Web Server / API Presenters Client Backend Business Logic Models
iOS Android View Models Presenters Web Server / API Client Backend Business Logic Models
class NewGamePresenter { C
fun model(): NewGameUi Model { } B
} A
class NewGamePresenter( private val gameStore : GameStore) { C
fun model(): NewGameUi Model { } B
} A
class NewGamePresenter( private val gameStore : GameStore) { C
fun model(): NewGameUi Model {
val totals = gameStore .totals()
return NewGameUiModel(totals. wins , totals. losses ) } B
} A
class GamePresenter
{ D
fun model(): GameUiModel { C
} B
} A
class GamePresenter( private val gameId : Long) { D
fun model(): GameUiModel { C
} B
} A
class GamePresenter(
private val gameId : Long,
private val gameStore : GameStore ) { D
fun model(): GameUiModel { C
} B
} A
class GamePresenter(
private val gameId : Long,
private val gameStore : GameStore ) { D
fun models(): Observable<GameUiModel> { C
} B
} A
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
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
iOS Android View Models Presenters Web Server / API Client Backend Business Logic Models
iOS Android View Models Presenters Web Server / API Client Backend Business Logic Models
iOS Web Android View Models Presenters Server / API Client Backend Business Logic Models
iOS Web Android View Models Presenters Server / API Client Backend Business Logic Models
iOS Web Android View Models Presenters Client Backend Server / API Business Logic Models
interface GameStore {
} A
interface GameStore {
fun totals(): Single<Totals>
data class Totals( val wins : Long, val losses : Long) } A
interface GameStore {
fun totals(): Single<Totals>
fun game(id: Long): Observable<Game>
data class Totals( val wins : Long, val losses : Long) } A
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
iOS Web Android View Models Presenters Client Backend Server / API Business Logic Models
iOS Web Android View Models Presenters Client Backend Server / API Business Logic Models
Android iOS Web Client Backend iOS Web Server / API Android View Models Presenters Business Logic Models
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 ()
}
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 ()
}
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
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
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
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
Android iOS Web Client Backend iOS Web Server / API
Android View Models Presenters Business Logic Models
Android iOS Web iOS Web Android View Models Presenters Client Backend Server / API Business Logic Models
Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models
Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models
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 {
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 ()
}
Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models
Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models
Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models
iOS Web Server / API Android Android iOS Web View Models Presenters Client Backend Business Logic Models
class GameView(context: Context, attrs: AttributeSet)
: Consumer<GamePresenter.UiModel> {
fun accept(model: GamePresenter.UiModel) {
// TODO bind to view...
} }
iOS ???
function update(model) {
// TODO bind to DOM/template/JSX/whatever...
}
@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 ... }
Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models
X
O
X
X X
O
O O
X
twitter.com/ github.com/ .com Possible Futures with Kotlin
jakewharton jakewharton jakewharton
An overview of why Kotlin exists, its syntax, and its potential cross-platform future.