KotlinConventions
|

Deep Dive Into Kotlin Conventions | Get | Set | In | RangeTo

We all know, Kotlin use the principle of a convention, instead of relying on types of  Java does, because this allows developers to adapt existing Java classes to the requirement of Kotlin language features. The set of interfaces implemented by a class is fixed, and Kotlin can’t modify an existing class so that it would implement additional interfaces.

What is Kotlin Conventions:

For Example, if your class defines a special method name plus , then, by convention you can use the + operator on the instance of this class. Because of that Kotlin refers to this technique as Kotlin Conventions. Similarly, the same technique applies on get, set, in, and on a rangeTo convention.

So, enough of this theory let’s see the example first of how we can use these conventions in our application.

1. Accessing Element By get Convention

You guy’s, already know that in Kotlin , you can access the elements in a Map similarly to how you access Arrays in java–via square brackets:

val value = map[key]

Meanwhile, it’s time to see how this works. In Kotlin , the index operator is one more convention. Reading the element using the index operator is translated into a call of get operator method. Generally, the method is already defined for the Map and MutableMap interfaces. Let’s see how to add a similar method for your own class:

fun main(args: Array<String>) {
    
    val p = Point(10, 20)
    val second = p[1]
    println(second)
}


data class Point(val x: Int, val y: Int)

operator fun Point.get(index: Int): Int {
    return when (index) {
        0 -> x
        1 -> y
        else ->
            throw IndexOutOfBoundsException("Invalid coordinate $index")
    }
}

// Output of above program
20

You see we use the square brackets reference the coordinates of the point. Similarly, all you need to do is to define a function name get and mark it as operator. Once you do that, the expression like p[1], where p has type Point, will be translated into calls to the get method.

GetKotlinConventionsNote: The parameter get can be any type, not just Int. For Example, when you indexing operator on a Map, the parameter type is the key type of the Map, which can be an arbitrary type. You can define multiple overloaded get methods with different parameter types if your collection can be accessed with different key types.

2. Assign Element By set Convention

The same goes for the set convention that lets you to change the value at a given index using a bracket index. Let’s define a mutable Point class and use that an example:

fun main(args: Array<String>) {
    val p = Point(10, 20)
    p[0] = 35
}


data class Point(var x: Int, var y: Int)

operator fun Point.set(index: Int, value: Int) {
    when (index) {
        0 -> x = value
        1 -> y = value
        else ->
            throw IndexOutOfBoundsException("Invalid coordinate $index")
    }
}

To use the index operator in the assignment, you just need to define a function name set. The last parameter to set receives the value used on the right side of the assignment and the other arguments are taken from the indices used inside the brackets.

setKotlinConvention3. The in Convention

One other operator supported by collections is the in operator, which is used to check whether an object belongs to a collection. The corresponding function is called contains. Let’s implement it so that you can use the in operator to check whether a point belongs to a rectangle.

data class Point(val x: Int, val y: Int)

data class Rectangle(val upperLeft: Point, val lowerRight: Point)

operator fun Rectangle.contains(p: Point): Boolean {
    return p.x in upperLeft.x until lowerRight.x &&
            p.y in upperLeft.y until lowerRight.y
}

fun main(args: Array<String>) {
    val firstPoint = Point(10, 20)
    val secondPoint = Point(50, 50)
    val rect = Rectangle(firstPoint, secondPoint)
    println(Point(15, 20) in rect)
    println(Point(8, 8) in rect)
}

// Output of above program

true
false

The object on the right side of in becomes the object on which the contains method is called and the object on the left side becomes the argument passed to the method. Furthermore, in the implementation of Rectangle.contains , you see we use the until standard library function to build an open range and then you use the in operator on a range to check that a point belongs to it or not.

inKotlinConvention4. The rangeTo Convention

To create a range, you use the .. syntax: for-instance,  1..10 enumerate all the numbers from 1 to 10. The .. operator under the hood call the rangeTo method:

rangeToFunctionExampleThe rangeTo function defines a range. Moreover, you can define this operator for your own class. But if your class define the Comparable interface, you don’t need that: you can create a range of any comparable elements by means of the Kotlin standard library.

Note: The library defines the rangeTo  function that can be called on any comparable element:

operator fun <T: Comparable<T>> T.rangeTo(that: T): ClosedRange<T>

This function returns a range that allows you to check whether different elements belong to it.

As an example, let’s see build a range of points using Point class.

data class Point(val x: Int, val y: Int) : Comparable<Point> {
    override fun compareTo(other: Point) = (this.x + y).compareTo(other.x + other.y)
}

fun main(args: Array<String>) {
    val ranges = Point(20, 20)..Point(20, 40)
    val firstResult = Point(25, 20) in ranges
    val secondResult = Point(10, 10) in ranges
    println(firstResult)
    println(secondResult)
}

// The output of above program :
true
false

The expression Point(20,20)..Point(20,40) is transformed into  Point(20,20).rangeTo(Potin(20,40)) by the compiler. The rangeTo isn’t a member of Point class but rather is an extension function on Comparable, as shown earlier. The  in operator in above program only return true, if the Point x and y coordinate value is in the range 40-60.

 

By defining the function named get,  set , and  contains, you can support the  [] and  in operators to make your class similar to  Kotlin collections.

That’s it. As a whole, this is my knowledge about Kotlin Conventions. I tried to learn from my mistakes, others’ and my experiences. I’ve been constantly finding the best approach.

I hope you liked this article. Besides this, if you have any feedback, feel free to comment below: I would be very happy to get suggestions.

Thank you for being here and keep reading…

Similar Posts