Skip to content

Instantly share code, notes, and snippets.

@praveenKajla
Last active October 14, 2017 12:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save praveenKajla/0a09819e39ba33b47d2c16619d0d56ad to your computer and use it in GitHub Desktop.
Save praveenKajla/0a09819e39ba33b47d2c16619d0d56ad to your computer and use it in GitHub Desktop.

01. Fields in Kotlin

Remember Classes in Kotlin cannot have fields.

However, sometimes it is necessary to have a backing field (A private field that stores the data exposed by a public property) when using custom accessors. For these purposes, Kotlin provides an automatic backing field which can be accessed using the field identifier:

Let's create a class Customer having mutable property (using the var keyword) lastPurchased. We also create custom getter and setter for this property.

class Customer(){

    var lastPurchased:Double = 0.0 // Property type is optional as kotlin provide type inference
        get() = field //field is built-in variable and can only be used in getter and setter
        set(value){
            if(value>100){
                field = value
            }
        }
}

Here getter and setter are optional as kotlin provide default getter and setter . But since we are conditionally setting the value we need our own getter and setter.

fun main(args: Array<String>) {

    val customer = Customer() // no new keyword needed to instantiate
    println(customer.lastPurchased)
    customer.lastPurchased = 200.0
    println(customer.lastPurchased)
    customer.lastPurchased = 50.0
    println(customer.lastPurchased)

}

If we run this :

output -> 
  0.0
  200.0
  200.0

A backing field for a property is automatically created if :

  • a custom getter or setter references it through the field identifier
  • default implementation of at least one of the accessors is used

For cases where field is not enough we can't just use backing field for whatever reasons , then the only way around it is to create a private property like :

class Customer(){

    private var myCustomField = 10
    
    ....

02. Late Initialization

Oftentimes we need to have late initialization of a property.

Let's create a controller of web for Customer class above that spits out some data from a repository (database)

interface Repository{
    fun getAll(): List<Customer>
}

class CustomerController(){

    var repository:Repository // ide would show "Property must be initialized or be abstract"

    fun index():String{
        return repository.getAll().toString()
    }
}

Now imagine we want repository to be a property that need to be initialized by some IoC container i.e. we are not passing this property as a part of constructor but i want it to be initialized later on .

So one solution is to make it nullable i.e.

class CustomerController(){

    var repository:Repository? = null
    
    fun index():String{
        return repository?.getAll().toString()
    }
}

But then every single time we access repository we need to suffix it with ?. And also we don't want this to be null or let people reading our code to assume that we want it to be null.

SO kotlin provide modifier lateinit to solve this problem :

class CustomerController(){

    lateinit var repository:Repository // tells the compiler that we are going to initialize it later on.
    
    ...

However this is not gonna make everything safe . If we run without initializing repository

fun main(args: Array<String>) {
    val cc = CustomerController()
    cc.index()
}

We won't get null reference but :

Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property repository has not been initialized
	at CustomerController.index(Class.kt:15)
	at ClassKt.main(Class.kt:21)

Which makes debugging easier .

03. Nested Classes

Much like nested functions or local functions we can have nested classes in kotlin.

Let's create a class DirectoryExplorer having function listFolder which also encapsulate the functionality to check permission whether a specific user can access that folder.

class DirectoryExplorer(){

    class PermissionCheck(){

        fun validatePermission(user: String) {

        }

    }

    fun listFolder(folder:String,user:String){

        val permissionCheck = PermissionCheck()
        permissionCheck.validatePermission(user)
    }
}

So we have PermissionCheck as nested class. Also we can access this nested class and create an instance of that.

fun main(args: Array<String>) {
    val de = DirectoryExplorer()
    val pc = DirectoryExplorer.PermissionCheck()
}

If you don't want it to be accessed or instantiated make it private.

Now what if we want to access properties of external class inside nested class. To do that we would have to use modifier inner as prefix to nested class.

class DirectoryExplorer(val user:String){

    inner class PermissionCheck(){
        fun validatePermission() {
            if(user != "Bruce"){

            }
        }
    }
}

fun main(args: Array<String>) {
    val de = DirectoryExplorer("Bruce")
    val pc = DirectoryExplorer.PermissionCheck() //Ide would show "Constructor of inner class PermissionCheck can be called only with receiver of containing class"
}

using inner modifer makes the nested class the part of the actual instance of the external class,that's why we can't access inner class simply.

So it would be accessible as a part of the actual instance of the class i.e.

...

    val pc = DirectoryExplorer().PermissionCheck() 

...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment