Kotlin Constructors

In this article, you will learn about constructors in Kotlin (both primary and secondary constructors) as well as initializer blocks with the help of examples.

A constructor is a concise way to initialize class properties.

It is a special member function that is called when an object is instantiated (created). However, how they work in Kotlin is slightly different.

In Kotlin, there are two constructors:

  • Primary constructor – concise way to initialize a class
  • Secondary constructor – allows you to put additional initialization logic

Primary Constructor

The primary constructor is part of the class header. Here’s an example:

class Person(val firstName: String, var age: Int) {
    // class body
}

The block of code surrounded by parentheses is the primary constructor: (val firstName: String, var age: Int).

The constructor declared two properties: firstName (read-only property as it’s declared using keyword val) and age (read-write property as it is declared with keyword var).


Example: Primary Constructor

fun main(args: Array<String>) {

    val person1 = Person("Joe", 25)

    println("First Name = ${person1.firstName}")
    println("Age = ${person1.age}")
}

class Person(val firstName: String, var age: Int) {

}

When you run the program, the output will be:

First Name = Joe
Age = 25

When the object of Person class is created, "Joe" and 25 values are passed as if Person is a function.

This initializes firstName and age properties of person1 object to "Joe" and 25 respectively.


There are other ways of using primary constructors.


Primary Constructor and Initializer Blocks

The primary constructor has a constrained syntax, and cannot contain any code.

To put the initilization code (not only code to initialize properties), initializer block is used. It is prefixed with init keyword. Let’s modify the above example with initializer block:

fun main(args: Array<String>) {
    val person1 = Person("joe", 25)
}

class Person(fName: String, personAge: Int) {
    val firstName: String
    var age: Int

    // initializer block
    init {
        firstName = fName.capitalize()
        age = personAge

        println("First Name = $firstName")
        println("Age = $age")
    }
}

When you run the program, the output will be:

First Name = Joe
Age = 25

Here, parameters fName and personAge inside the parenthesis accepts values "Joe" and 25 respectively when person1 object is created. However, fName and personAge are used without using var or val, and are not properties of the Person class.

The Person class has two properties firstName, and age are declared.

When person1 object is created, code inside initializer block is executed. The initializer block not only initializes its properties but also prints them.


Here is another way to perform the same task:

fun main(args: Array<String>) {
    val person1 = Person("joe", 25)
}

class Person(fName: String, personAge: Int) {
    val firstName = fName.capitalize()
    var age = personAge

    // initializer block
    init {
        println("First Name = $firstName")
        println("Age = $age")
    }
}

To distinguish the constructor parameter and property, different names are used (fName and firstName, and personAge and age). It’s more common to use _firstName and _age instead of completely different name for constructor parameters. For example:

class Person(_firstName: String, _age: Int) {
    val firstName = _firstName.capitalize()
    var age = _age

    // initializer block
    init {
        ... .. ...
    }
}

Default Value in Primary Constructor

You can provide default value to constructor parameters (similar to providing default arguments to functions). For example:

fun main(args: Array<String>) {

    println("person1 is instantiated")
    val person1 = Person("joe", 25)

    println("person2 is instantiated")
    val person2 = Person("Jack")

    println("person3 is instantiated")
    val person3 = Person()
}

class Person(_firstName: String = "UNKNOWN", _age: Int = 0) {
    val firstName = _firstName.capitalize()
    var age = _age

    // initializer block
    init {
        println("First Name = $firstName")
        println("Age = $age\n")
    }
}

When you run the program, the output will be:

First Name = Joe
Age = 25

person2 is instantiated
First Name = Jack
Age = 0

person3 is instantiated
First Name = UNKNOWN
Age = 0

Kotlin Secondary Constructor

In Kotlin, a class can also contain one or more secondary constructors. They are created using constructor keyword.

Secondary constructors are not that common in Kotlin. The most common use of secondary constructor comes up when you need to extend a class that provides multiple constructors that initialize the class in different ways. Be sure to check Kotlin Inheritance before you learn it.

Here’s how you can create a secondary constructor in Kotlin:

class Log {
    constructor(data: String) {
        // some code
    }
    constructor(data: String, numberOfData: Int) {
        // some code
    }
}

Here, the Log class has two secondary constructors, but no primary constructor.

You can extend the class as:

class Log {
    constructor(data: String) {
        // code
    }
    constructor(data: String, numberOfData: Int) {
        // code
    }
}

class AuthLog: Log {
    constructor(data: String): super(data) {
        // code
    }
    constructor(data: String, numberOfData: Int): super(data, numberOfData) {
        // code
    }
}

Here, constructors of the derived class AuthLog calls the corresponding constructor of the base class Log. For that, super() is used.

Calling constructor of base class from derived class.

In Kotlin, you can also call a constructor from another constructor of the same class (like in Java) using this().

class AuthLog: Log {
    constructor(data: String): this(data, 10) {
        // code
    }
    constructor(data: String, numberOfData: Int): super(data, numberOfData) {
        // code
    }
}
Calling constructor from the same class.

Example: Kotlin Secondary Constructor

fun main(args: Array<String>) {

    val p1 = AuthLog("Bad Password")
}

open class Log {
    var data: String = ""
    var numberOfData = 0
    constructor(_data: String) {

    }
    constructor(_data: String, _numberOfData: Int) {
        data = _data
        numberOfData = _numberOfData
        println("$data: $numberOfData times")
    }
}

class AuthLog: Log {
    constructor(_data: String): this("From AuthLog -> " + _data, 10) {
    }

    constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) {
    }
}

When you run the program, the output will be:

From AuthLog -> Bad Password: 10 times

Note: The secondary constructor must initialize the base class or delegate to another constructor (like in above example) if the class has no primary constructor.

Kotlin Functions

In this article, you’ll learn about functions; what functions are, its syntax and how to create a user-function in Kotlin.

In programming, function is a group of related statements that perform a specific task.

Functions are used to break a large program into smaller and modular chunks. For example, you need to create and color a circle based on input from the user. You can create two functions to solve this problem:

  • createCircle() Function
  • colorCircle() Function

Dividing a complex program into smaller components makes our program more organized and manageable.

Furthermore, it avoids repetition and makes code reusable.


Types of Functions

Depending on whether a function is defined by the user, or available in standard library, there are two types of functions:

  • Kotlin Standard Library Function
  • User-defined functions

Kotlin Standard Library Function

The standard library functions are built-in functions in Kotlin that are readily available for use. For example,

  • print() is a library function that prints message to the standard output stream (monitor).
  • sqrt() returns square root of a number (Double value)
fun main(args: Array<String>) {

    var number = 5.5
    print("Result = ${Math.sqrt(number)}")
}

When you run the program, the output will be:

Result = 2.345207879911715

Here is a link to the Kotlin Standard Library for you to explore.


User-defined Functions

As mentioned, you can create functions yourself. Such functions are called user-defined functions.


How to create a user-defined function in Kotlin?

Before you can use (call) a function, you need to define it.

Here’s how you can define a function in Kotlin:

fun callMe() {
    // function body
}

To define a function in Kotlin, fun keyword is used. Then comes the name of the function (identifier). Here, the name of the function is callMe.

In the above program, the parenthesis ( ) is empty. It means, this function doesn’t accept any argument. You will learn about arguments later in this article.

The codes inside curly braces { } is the body of the function.


How to call a function?

You have to call the function to run codes inside the body of the function. Here’s how:

callme()

This statement calls the callMe() function declared earlier.

Function call in Koltin

Example: Simple Function Program

fun callMe() {
    println("Printing from callMe() function.")
    println("This is cool (still printing from inside).")
}

fun main(args: Array<String>) {
    callMe()
    println("Printing outside from callMe() function.")
}

When you run the program, the output will be:

Printing from callMe() function.
This is cool (still printing from inside).
Printing outside from callMe() function.

The callMe() function in the above code doesn’t accept any argument.

Also, the function doesn’t return any value (return type is Unit).

Let’s take another function example. This function will accept arguments and also returns a value.


Example: Add Two Numbers Using Function

fun addNumbers(n1: Double, n2: Double): Int {
    val sum = n1 + n2
    val sumInteger = sum.toInt()
    return sumInteger
}

fun main(args: Array<String>) {
    val number1 = 12.2
    val number2 = 3.4
    val result: Int

    result = addNumbers(number1, number2)
    println("result = $result")
}

When you run the program, the output will be:

result = 15

How functions with arguments and return value work?

Here, two arguments number1 and number2 of type Double are passed to the addNumbers() function during function call. These arguments are called actual arguments.

result = addNumbers(number1, number2)

The parameters n1 and n2 accepts the passed arguments (in the function definition). These arguments are called formal arguments (or parameters).

Passing arguments to a function in Kotlin

In Kotlin, arguments are separated using commas. Also, the type of the formal argument must be explicitly typed.

Note that, the data type of actual and formal arguments should match, i.e., the data type of first actual argument should match the type of first formal argument. Similarly, the type of second actual argument must match the type of second formal argument and so on.


Here,

return sumInteger

is the return statement. This code terminates the addNumbers() function, and control of the program jumps to the main() function.

In the program, sumInteger is returned from addNumbers() function. This value is assigned to the variable result.

Return value from a function in Kotlin

Notice,

  • both sumInteger and result are of type Int.
  • the return type of the function is specified in the function definition.// return type is Int fun addNumbers(n1: Double, n2: Double): Int { … .. … }

If the function doesn’t return any value, its return type is Unit. It is optional to specify the return type in the function definition if the return type is Unit.


Example: Display Name by Using Function

fun main(args: Array<String>) {
    println(getName("John", "Doe"))
}

fun getName(firstName: String, lastName: String): String = "$firstName $lastName"

When you run the program, the output will be:

John Doe

Here, the getName() function takes two String arguments, and returns a String.

You can omit the curly braces { } of the function body and specify the body after = symbol if the function returns a single expression (like above example).

It is optional to explicitly declare the return type in such case because the return type can be inferred by the compiler. In the above example, you can replace

fun getName(firstName: String, lastName: String): String = "$firstName $lastName"

with

fun getName(firstName: String, lastName: String) = "$firstName $lastName"