Android Programming – Part 11 Kotlin Fundamentals ⅩⅠ: Advanced Concepts

The Beauty of OOP.

Just like Java, you can take advantage of OOP’s powerful concepts in Kotlin as well. This is the last post on Kotloin’s fundamentals, but you can take advantage of this knowledge not only in your future Kotlin projects but also in other OOP languages.

This is the very last post of Kotlin’s fundamental series, and we’ll start with enums. If you’re familiar with Java, you know what I’m talking about, don’t you? Also, what we’re going through in this post is really important and you can probably take advantage of the knowledge in other OOP languages as well.

Here’s a simple example of an enum in Kotlin.

enumSample.kt

fun main() {
    val input = Result.ERROR
        getResult(result = input)
}

fun getResult(result: Result) {
    return when(result) {
        Result.SUCCESS -> println("Success")
        Result.FAILURE -> println("Failure")
        Result.ERROR -> println("Error")
    }
}

enum class Result {
    SUCCESS,
    FAILURE,
    ERROR
}
$ java -jar enumSample.jar
Error

enumSample.kt

A little advanced version:

From here, things are getting a bit complicated but fun. First of all, you have to know that repository that is written in the code is sort of a temporary space where you can store a data’s state to which other functions access and get the current status – does it make sense? I mean, that’s pretty much what’s going on here.

Look at the code – for example, main calls Repository.startFetch() that temporarily plugs Result.LOADING into loadState, and then Repository.getCurrentState() gets the temporality stored Result.LOADING and plug it into result. Then, getResult function is called and branches its actions based on its when function, printing out the corresponding strings on the console. And it repeats the same process with different Repository‘s functions.

enumSample.kt

fun main() {
    // val input = Result.ERROR
    //     getResult(result = input)
    Repository.startFetch()
        getResult(result = Repository.getCurrentState())
        Repository.finishedFetch()
        getResult(result = Repository.getCurrentState())
        Repository.error()
        getResult(result = Repository.getCurrentState())
}

fun getResult(result: Result) {
    return when(result) {
        Result.SUCCESS -> println("Success")
        Result.FAILURE -> println("Failure")
        Result.ERROR -> println("Error")
        Result.IDLE -> println("Idle")
        Result.LOADING -> println("Loading")
    }
}

object Repository {
    private var loadState: Result = Result.IDLE
    private var dataFetched: String? = null
    fun startFetch() {
        loadState = Result.LOADING
        dataFetched = "data"
    }
    fun finishedFetch() {
        loadState = Result.SUCCESS
        dataFetched = null
    }
    fun error() {
        loadState = Result.ERROR
    }
    fun getCurrentState(): Result {
        return loadState
    }
}

enum class Result {
    SUCCESS,
    FAILURE,
    ERROR,
    IDLE,
    LOADING
}
$ java -jar enumSample.jar
Loading
Success
Error

Improved version

fun main() {
    // val input = Result.ERROR
    //     getResult(result = input)
    Repository.startFetch()
        getResult(result = Repository.getCurrentState())
        Repository.finishedFetch()
        getResult(result = Repository.getCurrentState())
        Repository.error()
        getResult(result = Repository.getCurrentState())
}

fun getResult(result: Result) {
    return when(result) {
        is Error -> {
            println(result.exception.toString())
        }
        is Success -> {
            println(result.dataFetched?: "Ensure you start the fatch function")
        }
        is Loading -> {
            println("Loading...")
        }
        is NotLoading -> {
            println("Idle...")
        }
        else -> println("N/A")
    }
}

object Repository {
    private var loadState: Result = NotLoading
    private var dataFetched: String? = null
    fun startFetch() {
        loadState = Loading
        dataFetched = "data"
    }
    fun finishedFetch() {
        loadState = Success(dataFetched)
        dataFetched = null
    }
    fun error() {
        loadState = Error(Exception("Exception"))
    }
    fun getCurrentState(): Result {
        return loadState
    }
}

abstract class Result

data class Success(val dataFetched: String?): Result()
data class Error(val exception: Exception): Result()
object NotLoading: Result()
object Loading: Result()

// enum class Result {
//     SUCCESS,
//     // FAILURE,
//     ERROR,
//     IDLE,
//     LOADING
// }
$ java -jar enumSample2.jar
Loading...
data
java.lang.Exception: Exception

Replacing enum with abstract class:

This is an important concept of Kotlin’s OOP and probably this is something you have already masted in Java or other OOP languages. Anyway, here enum is replaced by an abstract class Result, and Result is implemented by Success, Error, NotLoading, and Loading. Since the abstract class doesn’t have its specific data-type, such as String or Int, the implementation is quite flexible.

And this is the power of OOP: as you can see below, getResult function receives Result type data as its argument, and Result’s child classes, which implemented it, have various other specific data types. And this makes the whole coding process cleaner – this is the beauty and power of OOP.

fun getResult(result: Result)

enumSample3.kt

import java.io.IOException
import java.lang.NullPointerException

fun main() {
    // val input = Result.ERROR
    //     getResult(result = input)
    Repository.startFetch()
        getResult(result = Repository.getCurrentState())
        Repository.finishedFetch()
        getResult(result = Repository.getCurrentState())
        Repository.error()
        getResult(result = Repository.getCurrentState())
        Repository.anotherCustomFailure()
        getResult(result = Repository.getCurrentState())
        Repository.customFailure()
        getResult(result = Repository.getCurrentState())
}

fun getResult(result: Result) {
    return when(result) {
        is Error -> {
            println(result.exception.toString())
        }
        is Success -> {
            println(result.dataFetched?: "Ensure yoi start the fatch function")
        }
        is Loading -> {
            println("Loading...")
        }
        is NotLoading -> {
            println("Idle...")
        }
        is Failure.AnotherCustomFailure -> {
            println(result.anotherCustomFailure.toString())
        }
        is Failure.CustomFailure -> {
            println(result.customFailure.toString())
        }
    }
}

object Repository {
    private var loadState: Result = NotLoading
    private var dataFetched: String? = null
    fun startFetch() {
        loadState = Loading
        dataFetched = "data"
    }
    fun finishedFetch() {
        loadState = Success(dataFetched)
        dataFetched = null
    }
    fun error() {
        loadState = Error(Exception("Exception"))
    }
    fun getCurrentState(): Result {
        return loadState
    }
    fun anotherCustomFailure() {
        loadState = Failure.AnotherCustomFailure(anotherCustomFailure = NullPointerException("Something went wrong!"))
    }
    fun customFailure() {
        loadState = Failure.CustomFailure(customFailure = IOException("Custom Failure"))
    }
}

sealed class Result

data class Success(val dataFetched: String?): Result()
data class Error(val exception: Exception): Result()
object NotLoading: Result()
object Loading: Result()

sealed class Failure: Result() {
    data class CustomFailure(val customFailure: IOException): Failure()
    data class AnotherCustomFailure(val anotherCustomFailure: NullPointerException): Failure()
}

// enum class Result {
//     SUCCESS,
//     // FAILURE,
//     ERROR,
//     IDLE,
//     LOADING
// }
$ java -jar enumSample3.jar
Loading...
data
java.lang.Exception: Exception
java.lang.NullPointerException: Something went wrong!
java.io.IOException: Custom Failure

Leave a Reply