Mastering Kotlin's Object-Oriented Programming 101: Unleashing the Full Potential of Your Code.
Tags: android, kotlin, beginners, mobile
Published: 2023-04-10 14:44:22

`Hellooooo🥳️🥳️🥳️I am glad🤗 that you have joined me again in this Android development journey🚀. I am glad that you have decide to join me again on this exciting journey as we explore the world of kotlin for Android development.`

🚀Kotlin is a programming language that's gaining popularity due to its ability to combine object-oriented and functional programming paradigms.
🚀In this article, we'll explore Kotlin's object-oriented programming features and how they can be used to build efficient software applications. Whether you're a seasoned developer or just starting out, come with us on this journey to discover why Kotlin is worth learning.

**In this article, we are going to deep dive into one of the most important concepts of Kotlin:**

_**1. Functions**_
_**2. Classes and Objects**_
_**3. Interfaces and Inheritance**_
_**4. Class Inheritance**_

##1. Functions

- Functions help in writing the code once and re-using it in other parts of your code.

![kt functions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/carnz2tjywdj3z40lci7.png)
- Functions are used to break the code into smaller, more understandable, and reusable parts.

**_Variable scope and local functions_**

- Variables defined inside of a function are called local variables. They are visible only in their defined scope. 
- These variables can be used in the functions they are defined.

```
fun firstFunction () {
val name = "Google Office Zurich"
    println(name)
}
fun CarType () {
    val car = "Bently"
    firstFunction()
    println(car)
}
fun main () {
    CarType()
}

```
The output of the above code after calling the function `CarType()` in the main function is `Google Zurich Office` and `Bently`. `firstFunction` cannot be used to access the type of car becaude it is mentioned outside its scope.

- Local functions are defined inside other functions. They can only be used in their scope of the definition.
- Top-level functions do not have such limitations they can be used everywhere even in functions defined earlier in a file.
- Below is an example of a top-level function
```
fun calculateCircleArea(radius: Double): Double {
    return Math.PI * radius * radius
}
fun main () {
val area = calculateCircleArea(2.0)
println("The area of the circle is $area")
}
```
The output of the above code is `12.566370614359172`

**_Functions with Parameters and result_**

- `Parameters` are named variables that is defined as part of a function. They are specified using parenthesis after the function name.
- When you declare or write a function and you use as a parameter, when you want to call this function, you must supply the parameter with a value. The value supplied for this parameter is called `Argument`

```
fun calculateCircleArea(radius: Double): Double {
    return Math.PI * radius * radius
}
fun main () {
val area = calculateCircleArea(2.0)
println("The area of the circle is $area")
}
```
In the above code sample the name `radius: Double` is the parameter of the function `calculateCircleArea`. The Argument supplied for the `calculateCircleArea` function is `2.0`
- An _absolete function_ is a function that returns an integer value without a sign so this doesn't change positive values, but it returns all negative values into positive. 

```
fun absolete(value : Int) :Int {
    if(value >= 0){
        return value
    }else{
        return -value
    }
}
fun main () {
    println(absolete(123)) // output 123 
    println(absolete(-1)) // output 1
    println(absolete(9)) // output 9
}
```
**_Single expression functions_**

- In Kotlin, there is a special syntax for single expressions functions. Instead of braces with the body, you can use the equality sign, which specifies what should be returned.
```
fun triangleArea(width : Double, height : Double) : Double = width * height/2
fun main () {
val area = triangleArea(12.0,56.0)
println(area)
}
```
The ouput of the above code is `336.0`

**_Recursion_**

- These are functions that call themselves.
- A factorial function is an example of a recursive function. To implement such a function we might define a variable called `accumulator` with an initial value of 1, which will be used to accumulate all the numbers. Then, for each number from 1 to the number you calculate the factorial, you will modify the value by multiplying it by the next number.
- After that, all you need to do is to return the accumulator variable.

```
fun factorial(number : Int) : Int {
    var accumulator = 1
    for(i in 1..number){
       accumulator = accumulator * i 
    }
   return accumulator 
}
fun main () {
    println(factorial(5))
}
```
**_Default and Named arguments_**

- Default arguments that need not specify explicitly while calling a function. When a function is called without passing arguments the parameters become the default arguments.
```
fun student(name: String="Praveen", standard: String="IX" , roll_no: Int=11) {	
	println("Name of the student is: $name")
	println("Standard of the student is: $standard")
	println("Roll no of the student is: $roll_no")
}
fun main() {
	student()		 
}
```
The output of the above code is `Praveen` `IX` `11` since we have not passed any arguments in our student function in the main function.
- Named arguments allows to specify arguments while calling a function. With named arguments, you can pass arguments to a function in any order, as long as you specify the name of each argument.

```
fun student( name: String="Praveen", standard: String="IX" , roll_no: Int=11 ) {
	println("Name of the student is: $name")
	println("Standard of the student is: $standard")
	println("Roll no of the student is: $roll_no")
}

fun main(args: Array<String>) {
	val name_of_student = "Gaurav"
	val standard_of_student = "VIII"
	val roll_no_of_student = 25
student(name=name_of_student,roll_no=roll_no_of_student)
}
```
For this code to work we pass arguments with names as defined in function.

##2. Classes and Objects

- A `class` is like a template that defines what an object looks like and how it can be used.
- It specifies how the objects should be created and which methods and properties it consists of.

![Image kt obj](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d4yrzu8imapbmsyvmfbb.png)
- An `object` is an instance of a class. A type represents a category of objects eg an integer represents all integers.
- To define a class in kotlin you use the keyword `class` and specify the `name` of the class.

```
class Car {
    var brand = ""
    var model = ""
    var year = 0
}
```
- You will realize that when we use curly braces to define a class we must initialize the objects, we cannot leave them open but when we use brackets we don't have to initialize the class we only specify the type.
- When we use brackets to enclose the class we should use commas to separate different properties inside it.

```
class Car (
   var brand : String,
    var model : String,
    var year : Int
         )
```
**_Creating an object_**

- We can create an object of the `Car` class above called `objCar`, and then we can access the properties of objCar by using the dot `syntax (.)`

```
class Car (
   var brand : String,
    var model : String,
    var year : Int
         )
 fun main () {
     var objCar = Car(
     "Bently",
     "Mustang",
     2013
     )
      println( objCar.brand)
     println( objCar.model)
     println( objCar.year)
 }
```
- When we use the brackets to define the class we use the primary constructor property when specifying a value for a regular property.
- When we use the curly braces we define the properties of the class not as parameters as shown below.

```
class Car {
    var brand : String = ""
    var model : String = ""
    var year : Int = 0
         }
 fun main () {
     var objCar = Car()
     
     objCar.brand = "Bently"
     objCar.model = "Mustang"
     objCar.year = 2013
     
     println( objCar.brand)
     println( objCar.model)
     println( objCar.year)
 }
```
- We can also specify the property of a class inside a class body. First, we use curly brackets as shown below.

```
class Car (
    var brand : String,
    var model : String
          )
{
    var ObjCar : String = "$brand($model)"
}
 fun main () {
     var CarType = Car( brand = "Bently", model = "Mustang")
     println(CarType.ObjCar)
            }
```
The output of the above code will be `Bently(Mustang)`

**_Methods_**

- A method is a function associated with a class, for example a defined class. They are defined inside the class body. In other words, they are defined inside the curly braces.
- Methods have direct access to all the properties of a class as shown below

```
class Subject (val name : String)

{
    fun Teacher (course : String, grade : String) : Teaches {
        println("$name teaches $course well I got $grade grade")
        return Teaches(course,grade)
                             }
    fun TeachesWell (course : String, grade : String){
        println("Congratulations")
    //Methods can be used to call other methods    
        Teacher(course, grade)
               }
}

class Teaches (
    var course : String,
    var grade : String
              )

fun main () {
    val read = Subject ("Daniel")
    read.TeachesWell(course = "Physics", grade = "A")
}
```
- The output of the above code is
 
`Congratulations`
`Daniel teaches Physics well I got A grade`
- In order to call a method, you need to have an object. For instance, when you have a `class Dog` with a `method feed`, to call this method outside the class, you need to first have an object of type Dog.

```
class Dog (var name: String)
{
    var hunger : Int = 62
    
    fun feed (){
        println("Feeding $name")
        hunger = 0
    }
    
}

fun main () {
    var dog = Dog ("Rex")
    dog.feed()
}
```
The output of the above code is `feeding Rex`. 
- Inside the method, we use the `name `and `hunger` properties from the object that was used during the call. In a way, It is similar to defining `feed` as a top-level function and parsing `Dog` as an argument.
- In methods, you can access members implicitly. For instance in the below code use just `name`, not `dog.name`

```
class Dog (var name : String)
{
    var hunger : Int = 62
}
    
fun feed (dog : Dog){
     println("Feeding ${dog.name}")
     dog.hunger = 0
    }

fun main () {
    var dog = Dog ("Rex")
    feed(dog)
}
```
The output of the above code is `feeding Rex`. 
- When you call methods, the object of their class is passed to their class body. This is called a **receiver**. 
- A receiver can be accessed using `this keyword` also known as _reciever reference_. So if you want to reference an object used to call a method inside this method, use `this keyword`.

```
class Dog(var name : String){
    var hunger = 62
    
    fun feed (){
      //Receiver
      var currentDog : Dog = this
        println("Feeding ${currentDog.name}")
        currentDog.hunger = 0
    }
}

fun main (){
    var dog = Dog("Rex")
    dog.feed()
}
```
- when you call methods or properties inside methods, such as when  you call name, you are calling methods or properties in the receiver, so its like calling `this.name`

```
class Dog(var name : String){
    var hunger = 62
    
    fun feed (){
      //Receiver
      //var currentDog : Dog = this
        println("Feeding ${this.name}")
        this.hunger = 0
    }
}

fun main (){
    var dog = Dog("Rex")
    dog.feed()
}
```
- `this` keyword can be used to call methods or properties and sometimes it can be used explicitly.
- One example might be when you have a method parameter and class property with the same name. Like in the below class, there is a property `name` and a method `changeName` with a parameter `name`. So if you see `name ` inside the class, you will have a value of the parameter. To access the property use `this.name`

```
class User (var name : String) {
    fun changeName (name : String){
        println("Change name from ${this.name} to $name")
        this.name = name
    }
}

fun main () {
    val user = User("Alpha")
    user.changeName("Beta")
    println(user.name)
}
```
## 3. Interfaces and Inheritance
- An _interface_ is a collection of abstract methods and properties that define a common contract for classes that implement the interface.

![Image kt interface](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktgsbf2tgpc9fb82i1pg.png)
- Interfaces cannot be instantiated directly.

**_Creating interfaces_**
- Interface is defined by the keyword `Interface` followed by the name of the interface and curly braces.
- Functions and properties of the interface reside inside the curly braces.

```
interface Fruit {
  fun  BitterFruit()
  fun SweetFruit()
}
```
**_Implementing Interfaces_**
- Interfaces are implemented by classes or objects.
- Classes or objects implementing the interface should be followed by a colon and the name of the interface which is to be implemented. eg

```
interface Fruit {
    
   fun BitterFruit()
   fun SweetFruit()
   
}

class TypeFruit: Fruit {
   
    override fun BitterFruit() {
        println("Lemon is a bitter fruit")
    }
    override fun SweetFruit() {
        println("Apple is sweet fruit ")
    }
}

fun main () {
    val fruit = TypeFruit ()
    
    fruit.BitterFruit()
    fruit.SweetFruit()
}
```
- We are using the keyword override in our functions because they were specified in the interface.

**_Default values and Default methods_**

- Methods can have default values as parameters which are used when no value is passed during the function call.

```
interface Sum {
    // 10 and 20 are default values
    fun add( firstNum : Int = 10,secondNum : Int = 20)
    fun output () {
        println("This is an example of an addition of numbers")
    }
}
class Addition (): Sum {
    override fun add (firstNum : Int, secondNum : Int){
        val SumOfNumbers = firstNum + secondNum
        println("The sum of $firstNum and $secondNum is $SumOfNumbers")
    }
    override fun output () {
        super.output()
        println("Sum of two numbers")
    } 
}
fun main () {
    val addition = Addition()
    //We are overriding the default values with new arguments
    addition.add(30,30)
    addition.output()
}
```

The output is `60` and not `30`. In our main function, we have changed our default values to hold `30` in both firstNum and secondNum.
- The super keyword is used to call the default implementation of print specified in the inheritance.

**_Inheritance properties in interface_**

- Interfaces can contain properties that cannot be instantiated hence no backfield to hold their values. The fields in the interface are either left abstract or are provided an implementation.

![Image inheritance](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/um78mxpu7bto0xncmi70.png)
-Interfaces can also inherit others interfaces adding its own properties and methods in both the interfaces.
- An interface can inherit more than interface.
- The value of `length` and `breadth` are the properties of the interface dimensions.

```
interface Dimensions {
    val length : Double
    val breadth : Double
}
interface CalculateParameters : Dimensions {
    fun area ()
    fun perimeter ()
}
class Calculations () : CalculateParameters {
    override val length : Double
    get() = 40.0
    override val breadth : Double
    get() = 60.0
    
    override fun area () {
        println("The area is ${length * breadth}")
    }
    override fun perimeter () {
        println("The perimeter is ${2*(length + breadth)}")
    }
}
fun main () {
    var obj = Calculations ()
    // The area is 2400.0
    obj.area()
    // The perimeter is 200.0
    obj.perimeter()
}
```
- Kotlin has multiple interface implementations. A class can implement more than one interface provided that it has a definition for all the numbers of the interface.
- A class can only inherit one class.

```
interface Dimensions {
    val length : Double
    val breadth : Double
}
interface CalculateParameters {
    fun area ()
    fun perimeter ()
}
class Calculations () : Dimensions, CalculateParameters {
    override val length : Double
    get() = 40.0
    override val breadth : Double
    get() = 60.0
    
    override fun area () {
        println("The area is ${length * breadth}")
    }
    override fun perimeter () {
        println("The perimeter is ${2*(length + breadth)}")
    }
}
fun main () {
    var obj = Calculations ()
    // The area is 2400.0
    obj.area()
    // The perimeter is 200.0
    obj.perimeter()
}
```
## 4. Class Inheritance
- During class inheritance

![Image kt inh](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v5osgh14380hiy78fpzf.jpg)
_1.  One must define a class that extends from another class._
_2.  The class to be inherited must be open._
_3.  One must introduce the same modifications to the behavior._

- When one class inherits from another, it takes all the previous class methods and properties. It becomes its subclass, which means that it can be used wherever its parent is expected.

```
open class Klass () {
    fun students () {
        println("There are 50 students in the class")
    }
    fun subject () {
        println("The class takes chemistry as a compulsory subject")
    }
   }
class Teacher () : Klass() {
    fun teaches () {
        println("The teacher teaches all the 50 students chemistry")
    }
   
}
fun main () {
    val teach = Teacher ()
    teach.students()
    teach.subject()
}
```
- class Klass is the super or the primary class while class Teacher is the subclass or the secondary class.

**_Visibility Modifiers in Classes_**
 
- To make encapsulation possible you need to hide some properties and methods so that they can be used inside of a class but not outside of it. To do that you use the private visibility modifier before a function or a property you want to hide.
- **Private** means that a particular property or a function can only be used in that class.
- **Protected** means that a property can be used inside classes that are open or abstract.
- **Internal** means that an element will be visible throughout the same module. 


**💫💫Thank you for taking the time to read my article, I appreciate your interest and support.😇😇🥳🥳**
![Thank you](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/45oa31ygulwblc2vzmhp.jpg)