5 minutes read

In this topic, we will consider the issue of naming arguments in overridden functions. This subject is important for those who want to write pure and understandable code, which is one of the main goals of the Kotlin language.

Basics of function overrides

In Kotlin, as in most object-oriented programming languages, classes can be inherited from each other. When inherited, classes can override the functions of the parent class to modify or extend their behavior. To do that, Kotlin uses the override keyword. Let's take a simple example:

open class Animal {
    open fun makeSound() {
        println("The animal makes a sound")
    }
}

class Dog : Animal() {
    override fun makeSound() {
        println("The dog barks")
    }
}

Here, the Animal base class has an open makeSound() function. The Dog class inherits from the Animal class and overrides the makeSound() function.

Overriding properties

The primary mechanism works for properties as it does for methods. When redeclaring properties from a superclass in a derived class, they must be preceded by the override keyword and possess a compatible type. A declared property can be overridden either by a property featuring an initializer or one with a get method. Overriding a val property with a var property is allowed, but the opposite is not permitted. This is due to the fact that a val property inherently includes a get method, and when overridden as a var, a set method is also declared in the derived class:

open class Shape {
    open val vertexCount: Int = 0
}

class Triangle : Shape() {
    override val vertexCount = 3
}

Another example:

interface Shape {
    val vertexCount: Int
}


class Polygon : Shape {
    override var vertexCount: Int = 0  // Can be set to any number later
}

Argument names in overridden functions

Functions can often have several arguments, and to improve the readability of code in Kotlin, you can use named arguments when calling a function. However, you need to be careful when naming arguments in overridden functions to avoid confusion and errors. It is important to keep argument names from the parent class to ensure compatibility with function calls that use named arguments.

Suppose we have the following basic class:

open class Shape {
    open fun draw(color: String, strokeWidth: Int) {
        println("Drawing a shape with the color $color and stroke width $strokeWidth")
    }
}

If we want to redefine the draw() function in a derived class, we must store the argument names:

class Circle : Shape() {
    override fun draw(color: String, strokeWidth: Int) {
        println("Drawing a circle with the color $color and stroke width $strokeWidth")
    }
}

Now, if we call the draw() function using named arguments, the code will work correctly:

fun main() {
    val shape: Shape = Circle()
    shape.draw(color = "red", strokeWidth = 3)

Let's now look at a more complex example with named arguments in overridden functions.

open class Vehicle {
    open fun move(speed: Int, direction: String) {
        println("The vehicle is moving at $speed km/h $direction")
    }
}

class Car : Vehicle() {
    override fun move(speed: Int, direction: String) {
        println("The car is moving at $speed km/h $direction")
    }
}

class Bicycle : Vehicle() {
    override fun move(speed: Int, direction: String) {
        println("The bicycle is moving at $speed km/h $direction")
    }
}

In the above example, we have a base class Vehicle and two class derivatives: Car and Bicycle. All classes have a move() function, which takes two arguments: speed and direction. In the derived classes, the move() function is overridden while preserving the argument names. This allows us to use named arguments without problems:

fun main() {
    val vehicle1: Vehicle = Car()
    val vehicle2: Vehicle = Bicycle()

    vehicle1.move(speed = 60, direction = "north")
    vehicle2.move(speed = 15, direction = "south")
}

The output will be:

The car is moving at 60 km/h north
The bicycle is moving at 15 km/h south

Argument naming guidelines

  • Always save argument names when overriding functions. This ensures compatibility with function calls that use named arguments.
  • Use meaningful argument names that reflect their purpose. This makes it easier to read and understand the code.
  • Use named arguments when calling functions with a large number of arguments or with arguments whose values are difficult to understand from the context. This will make the code more readable and understandable.

Conclusion

In this topic, we've looked at the importance of keeping argument names when redefining functions in Kotlin. This ensures compatibility with function calls that use named arguments and makes code more readable and understandable. When using named arguments, it is important to follow the naming guidelines and try to select meaningful names that do not trigger the assignment of arguments. We've also touched on the issue of property overriding, as well as the possibility of changing the val property to var in overridden properties.

30 learners liked this piece of theory. 3 didn't like it. What about you?
Report a typo