An intro to functional programming with Kotlin.
How can we leverage Kotlin to write code in a more functional approach rather than just write java-style imperative code with addition of 'var' and 'val'?
7. RECURSIONS
THE ITERATIVE WAY
fun Context?.findActivity(): Activity? {
var context = this
while (context is ContextWrapper) {
if (context is Activity) {
return context
}
context = context.baseContext
}
return null
}
8. RECURSIONS
THE RECURSIVE WAY
fun Context?.findActivity(): Activity? =
when (this) {
is Activity -> this
is ContextWrapper -> this.baseContext.findActivity()
else -> null
}
9. RECURSIONS
THE (TAIL)RECURSIVE WAY
tailrec fun Context?.findActivity(): Activity? =
when (this) {
is Activity -> this
is ContextWrapper -> this.baseContext.findActivity()
else -> null
}
40. YOU MIGHT NOT THINK THAT PROGRAMMERS ARE
ARTISTS, BUT PROGRAMMING IS AN EXTREMELY
CREATIVE PROFESSION. IT'S LOGIC-BASED
CREATIVITY.
John Romero
MAKE RX CLEARER
41. ENABLE FUNCTIONAL ARCHITECTURE
IMMUTABLE VALUE TYPES
▸ have no identity
▸ defined by the set of values they hold
▸ overrides equals, hashCode and toString
▸ builder pattern (?)
44. ENABLE FUNCTIONAL ARCHITECTURE
IMMUTABLE VALUE TYPES - DATA CLASS
data class RepositoryResponse(val id: Long, val name: String,
val fullName: String, val owner: UserResponse,
val htmlUri: String, val description: String,
val uri: String)
45. ENABLE FUNCTIONAL ARCHITECTURE
IMMUTABLE VALUE TYPES - DATA CLASS
data class RepositoryResponse(val id: Long, val name: String,
val fullName: String, val owner: UserResponse,
val htmlUri: String, val description: String,
val uri: String)
val owner: UserResponse = TODO("stub")
val response = RepositoryResponse(id = 33768, name = "restor1",
fullName = "Or Noyman", owner = owner, htmlUri = "...",
description = "...", uri = "...")
46. ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
▸ model all possible outcomes as data types
▸ represent through restricted class hierarchies
▸ leverage ‘when’ expressions
48. ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult>
sealed class FetchRepositoriesResult
49. ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult>
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
50. ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
51. ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
52. ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
53. ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
54. ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
55. ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
56. ENABLE FUNCTIONAL ARCHITECTURE
WHEN
fun renderFetchRepositories() {
fetchRepositories("JakeWharton")
.observeOn(AndroidSchedulers.mainThread())
.subscribe { response ->
when (response) {
is FetchRepositoriesLoading -> showShimmer()
is FetchRepositoriesError -> showError()
is FetchRepositoriesOk -> renderRepositories(response.repo)
}
}
}
57. ENABLE FUNCTIONAL ARCHITECTURE
WHEN
fun renderFetchRepositories() {
fetchRepositories("JakeWharton")
.observeOn(AndroidSchedulers.mainThread())
.subscribe { response ->
when (response) {
is FetchRepositoriesLoading -> showShimmer()
is FetchRepositoriesError -> showError()
is FetchRepositoriesOk -> renderRepositories(response.repo)
}
}
}
58. ENABLE FUNCTIONAL ARCHITECTURE
WHEN
fun renderFetchRepositories() {
fetchRepositories("JakeWharton")
.observeOn(AndroidSchedulers.mainThread())
.subscribe { response ->
when (response) {
is FetchRepositoriesLoading -> showShimmer()
is FetchRepositoriesError -> showError()
is FetchRepositoriesOk -> renderRepositories(response.repo)
}
}
}
59. ENABLE FUNCTIONAL ARCHITECTURE
WHEN
fun renderFetchRepositories() {
fetchRepositories("JakeWharton")
.observeOn(AndroidSchedulers.mainThread())
.subscribe { response ->
when (response) {
is FetchRepositoriesLoading -> showShimmer()
is FetchRepositoriesError -> showError()
is FetchRepositoriesOk -> renderRepositories(response.repo)
}
}
}
63. ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
64. ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
sealed class Event
sealed class FetchRepositoriesResult: Event()
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
sealed class FetchUserResult: Event()
object FetchUserLoading : FetchUserResult()
object FetchUserError : FetchUserResult()
data class FetchUserOk(val user: UserResponse)
: FetchUserResult()
65. ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
sealed class Event
sealed class FetchRepositoriesResult: Event()
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
sealed class FetchUserResult: Event()
object FetchUserLoading : FetchUserResult()
object FetchUserError : FetchUserResult()
data class FetchUserOk(val user: UserResponse)
: FetchUserResult()
66. ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
data class ViewState(val isLoadingUser: Boolean,
val isErrorUser: Boolean,
val user: UserResponse?,
val isLoadingRepos: Boolean,
val isErrorRepos: Boolean,
val repos: List<RepositoryResponse>?)