Kotlin provides many features that enhance the readability and expressiveness of code. One such feature is infix notation, which allows calling certain functions in a more natural way, similar to how operators work. In this blog, we’ll explore infix functions in Kotlin, provide practical examples, and even inspect the Java bytecode to understand how they work under the hood.
What is Infix Notation?
Infix notation in Kotlin is a way to call functions without using dots and parentheses. This can make code more readable, especially when working with operations that resemble mathematical expressions.
To define an infix function, it must meet these criteria:
It must be a member function or an extension function.
It must have only one parameter.
It must be marked with the
infix
keyword.
Syntax:
infix fun ClassName.functionName(parameter: Type): ReturnType
Let’s see a simple example.
Example 1: Creating an Infix Function
Here’s a basic implementation of an infix function:
class Calculator {
infix fun add(value: Int): Int {
return value + 10
}
}
fun main() {
val calculator = Calculator()
val result = calculator add 5 // Using infix notation
println(result) // Output: 15
}
Without infix notation, the function call would look like this:
val result = calculator.add(5)
Both calls are valid, but the infix notation makes it more readable.
Example 2: Infix Function for Operator Overloading
You can also use infix functions for custom operations. Let’s implement a Pair
creation using infix notation:
infix fun String.concatWith(other: String): String {
return this + " " + other
}
fun main() {
val fullName = "Kotlin" concatWith "Programming"
println(fullName) // Output: Kotlin Programming
}
This makes it look more natural compared to "Kotlin".concatWith("Programming")
.
Example 3: Using Infix Notation with Built-in Functions
Kotlin provides several built-in infix functions. One popular example is to
, which creates a Pair
:
fun main() {
val pair = "One" to 1 // Equivalent to Pair("One", 1)
println(pair) // Output: (One, 1)
}
Kotlin Infix to Java Bytecode
To understand how infix functions are compiled, let’s analyze the bytecode conversion of our example.
Consider this Kotlin code:
class MathOperation {
infix fun multiply(value: Int): Int {
return value * 2
}
}
fun main() {
val operation = MathOperation()
val result = operation multiply 4
println(result)
}
Java Bytecode (Decompiled to Java)
After compiling to JVM bytecode and decompiling to Java, the equivalent Java code looks like this:
public final class MathOperation {
public final int multiply(int value) {
return value * 2;
}
}
public final class Main {
public static void main(String[] args) {
MathOperation operation = new MathOperation();
int result = operation.multiply(4); // No infix in Java
System.out.println(result);
}
}
Observations:
The infix notation is syntactic sugar in Kotlin and is not reflected in the bytecode.
The function is compiled into a standard Java method call.
The JVM treats it as a normal function invocation, meaning there is no runtime overhead.
When to Use Infix Notation
Use Infix Notation When:
✔ The function performs a simple, self-explanatory operation.
✔ The function makes the code more readable.
✔ It mimics natural language expressions.
Avoid Infix Notation When:
❌ The function has complex logic.
❌ It reduces clarity instead of improving readability.
❌ The function has multiple parameters (infix works only with one argument).
Conclusion
Infix functions in Kotlin make code more readable and expressive, especially when dealing with operations that resemble mathematical expressions. However, under the hood, they compile to standard Java method calls, making them efficient with no additional runtime overhead.
By using infix functions wisely, you can write clean, concise, and more readable Kotlin code.