Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of inner class in kotlin?

Tags:

java

kotlin

I am new to kotlin. i am going through Nested class and inner class concepts in kotlin. Below is a example of nested class.

 fun main(args: Array<String>) {
   val demo = Outer.Nested().foo() // calling nested class method
   print(demo)
}
class Outer {
   class Nested {
      fun foo() = "Hello world"
   }
}

which gives output as

Hello world

here is the example of inner class.

fun main(args: Array<String>) {
   val demo = Outer().Nested().foo() // calling inner class method
   print(demo)
}
class Outer {
   private val welcomeMessage: String = "Hello world"
   inner class Nested {
      fun foo() = welcomeMessage
   }
}

which gives the outputs as

Hello world

my question is when nested class can perform the same operation as that of inner class . what is the purpose of inner class ?why we need inner class in real time?

like image 525
Gaju Kollur Avatar asked Dec 21 '19 12:12

Gaju Kollur


2 Answers

Nested class itself is a rather straightforward idea of one concept being logically dependent on another, wider concept. You would like to declare a new nested class whenever you find yourself describing a building block of such a wider concept you do not expect to ever show up in your business logic on its own out of thin air. Therefore, an instance of such a class is accessed via the definition of the class it is nested in.

Take for an example the following structure:

class Parrot(val name: String): Animal {

    //vals and vars useful for a parrot

    class HealthyConditions {
        val featherColour: String // Does not really apply to Dogs, Cats, Fish, etc.
        val cageSize: Size // Does not really apply to Dogs, Cats, Fish, etc.
        val weightInGrammes: Int
        val dailySleepInHours: Int

        fun isUnderweight(currentWeightInGrammes: Int): Boolean {
            return currentWeightInGrammes < weightInGrammes
        }
    }
}

Now, the concept of healthy living conditions is common and important for any Animal this system may describe, but from one species to another there are multiple completely different factors to take into consideration. Trying to prepare a single common HealthyConditions<Animal> class for all of them at once will likely lead to unreadable and hard to maintain code, full of ifs and elses. Therefore, it may make more sense for the developer to define concise, tidy nested classes for each Animal on its own. Later on, these will be accessed through Parrot.HealthyConditions(), Cat.HealthyConditions(), etc. instead of HealthyConditions.getForSpecies(animal).


Inner class is a Kotlin concept built on top of the idea of a nested class. While some details are very specific for a given concept and therefore are being described as nested classes, what if those details vary even further depending on the wider concept's instance? Then accessing it using the class definition may not be all it takes to operate properly. Inner classes are therefore accessed through the call to an instance of the class they are an inner class of.

Let's get back to our Parrot shall we?

class Parrot(val name: String, var age: Int): Animal {

    //vals and vars useful for a parrot

    inner class HealthyConditions {
        val featherColour: String // Does not really apply to Dogs, Cats, Fish, etc.
        val cageSize: Size // Does not really apply to Dogs, Cats, Fish, etc.
        val weightInGrammesByAge: Map<Int, Int>
        val dailySleepInHoursByAge: Int<Int, Int>
        
        /** variable 'age' from the Parrot class can be accessed only because the HealthyConditions class is marked inner!  */
        fun isUnderweight(currentWeightInGrammes: Int): Boolean {
            return weightInGrammesByAge[age] > currentWeightInGrammes
        }
    }
}

How much a healthy Parrot should weigh changes over the course of the said parrot's life. A hatchling weighing a couple hundreds of grams is fine but a grown individual under 2 kilograms might need some attention. Therefore, the question of whether or not a Parrot is underweight at X grams cannot be answered easily, but should we ask if Bob the Parrot should gain some weight, we could use what we know about Bob to determine the answer. In order to do that, the HealthyConditions class will be accessed through Parrot("Bob", 5).HealthyConditions().


Now, to top it off, you might still wonder if accessing parent class properties is really useful for the inner class. After all, you could simply provide the age value wherever you call the isUnderweight() function, right? That is true, of course, but when discussing nested classes we decided each Animal deserves their own HealthyConditions implementation. For a Dog class, the breed of the dog is just as important in determining its correct weight as is its age. For yet other species, the gender will also be of importance. Meaning that, without direct access of the inner class to its parent's properties, Healthcheck interface's function checkIfUnderweight() would have to accept awfully lots of different, probably nullable, variables in order to be applicable to all different kinds of animals in the system.


I took a lot of time talking over the concept without many code samples but from what I understood you do not struggle with the implementation, but with the justification for even implementing the code in the first place. Also, forgive me if the "Animal classes" example I came up with may appear dumbed down - the truth is it was the first I came up with. ;)

Anyways, I hope this short read may help you understand the concept and its use cases better. Safe coding and may the bugs stay away from you!

like image 87
ryfterek Avatar answered Nov 04 '22 14:11

ryfterek


The official Kotlin documentation is quite self-explanatory:

A nested class marked as inner can access the members of its outer class. Inner classes carry a reference to an object of an outer class:

Perhaps you do not understand what this means.

Concretely, in your code sample, you can only access welcomeMessage which is defined in Outer from code in Nested when Nested is marked as inner. Try removing inner, and your code won't compile.

like image 24
Steven Jeuris Avatar answered Nov 04 '22 15:11

Steven Jeuris