Infix Functions in Kotlin

Learn via video courses
Topics Covered

Overview

One of the notable features of Kotlin is that it offers a unique way to streamline code and enhance its readability. The instruments to do this are called infix functions in Kotlin. This article offers a comprehensive introduction to infix functions in Kotlin, shedding light on their purpose, syntax, and the advantages they bring to the table. Let's dive right in!

Introduction

Infix functions in Kotlin are a special type of function that enables a more intuitive and human-readable coding experience. With infix functions in Kotlin, you can perform operations on objects in a manner that closely resembles natural language. These functions are particularly well-suited for binary operations where two elements interact to produce a result.

When a function is marked with the infix keyword, it can be invoked using infix notation, which means making the call without using parentheses or the customary dot.

Kotlin's infix function notation can be categorised into two distinct types:

  1. Standard library infix function notation
  2. User-defined infix function notation

Standard Library Infix Function Notation

Standard library infix function notation in Kotlin refers to the practice of invoking built-in functions from the Kotlin standard library using a specific syntax known as "infix notation." Infix notation enables you to call functions more intuitively and concisely, resembling human-readable language expressions. They can be called directly on an object using a specialized syntax that omits the traditional dot and parentheses.

The Kotlin standard library provides a collection of infix functions that cover common operations like arithmetic, bitwise operations, logical operations, etc.

Example 1: Creating a Pair

Consider the following code snippet.

Code:

Output:

Explanation:

In the above example, we have used the following methods to create a pair.

  1. Using Dot and Parentheses (Pair class constructor): We use the standard way to create a pair using the Pair class constructor: Pair(key, value). Here, we use dot notation by directly calling the Pair constructor and passing the key and value as arguments enclosed in parentheses. The result is stored in the pair1 variable.

  2. Using Infix Notation (to function): Here we have used infix functions in Kotlin to create pairs more concisely and naturally. Using infix notation, we write key to value, which resembles a key-value pairing in everyday language. The to function creates a pair where the first value is the key and the second value is the value. The result is stored in the pair2 variable.

Example 2: Checking If a String Contains a Substring

Consider the following code snippet.

Code:

Output:

Explanation:

In the above example, we have used the following methods to check if a string contains a substring

  1. Using Dot and Parentheses (contains function): We use the contains function of the String class to check if the text contains the substring "Hello". The function call is written as text.contains("Hello") using dot notation and parentheses. The result of the contains function call is stored in the containsHello1 variable.

  2. Using Infix Notation (in operator): We use the infix notation substring in the string where we check if "Hello" is in the text string. The in operator is used as an infix function here. The result of the in operation is stored in the containsHello2 variable.

Example 3: Using Decrement and Increment Operators

Consider the following code snippet.

Output:

Explanation:

  1. Here, we have used decrement and increment operators using infix notations.
  2. ++a evaluates to a(12)+1a(12) + 1 so it prints 13
  3. a.inc() also represents a(13)+1a(13) + 1 so it prints 14
  4. –-b evaluates to KaTeX parse error: Expected 'EOF', got '–' at position 7: b(14) –̲ 1 = 13
  5. b.dec() also represents b(13)1=12b(13)- 1 = 12

User-defined Infix Function Notation

User-defined infix function notation in Kotlin allows you to create custom functions that can be called using infix notation. This feature empowers you to make your code more expressive and readable by using operator-like syntax for specific operations.

To define user-defined infix functions in Kotlin, you need to follow these guidelines:

  1. Use the Infix Modifier: Begin the function definition with the infix modifier. This modifier informs the compiler that the function can be called using infix notation.
  2. Define Function Signature: Specify the function name, parameters, and return type.
  3. Function Body: Write the logic of the function within the curly braces.

Here's a generic syntax for defining a user-defined infix function:

Example 1: Custom Arithmetic Operation

Let's create a simple example to illustrate user-defined infix function notation for a custom arithmetic operation.

Code:

Output:

Explanation:

In this example, we've defined a user-defined infix function named myCustomAddition that adds two integers along with an additional value (10). The infix modifier allows us to use this function using infix notation.

When you call the myCustomAddition function using infix notation (a myCustomAddition b), it essentially translates to a.myCustomAddition(b). The custom function's behaviour is the addition of a, b, and 10, resulting in a final value that is printed as the result.

Example 2: Custom Path Composition

Output:

Explanation:

In this example, we've defined a Path class to represent segments of a path. We've also defined an infix function join that allows two Path instances to be joined together using infix notation. This custom function provides a more intuitive way to compose paths.

Precedence of Infix Function with Operators

Operator precedence refers to the rules that determine the order in which operators are evaluated in an expression. Operator precedence ensures that expressions are evaluated consistently and predictably. When you have multiple operators in an expression, precedence rules help determine which operations are performed first.

The order of operations becomes crucial during the execution of instructions. When invoking infix functions in Kotlin, their precedence ranks lower than arithmetic operators, type casts, and the rangeTo operator. The subsequent expressions hold the same meaning:

In the above expressions:

  1. shr is the right shift operator for bit manipulation. It shifts the bits of the left operand to the right by the number of positions specified by the right operand.
  2. until is an inclusive range operator in Kotlin. It ranges from the left operand (inclusive) to the right operand (exclusive).
  3. union is used to create a union of two sets in Kotlin.
  4. as is used for typecasting.

Conversely, infix function calls take precedence over boolean operators && and ||, is- and in-checks, along with various other operators. The following expressions are also equivalent:

In the above expressions:

  1. xor is the bitwise XOR operator in Kotlin, which returns true if exactly one of its operands is true.
  2. || is the logical OR operator.
  3. in is used to check if an element is contained within a collection or range in Kotlin.

Conclusion

  1. Kotlin's infix functions enhance code readability, expressing operations in a more natural, language-like syntax for improved understanding, especially in binary operations.
  2. Developers can use infix functions in Kotlin to define custom notations for specific operations, tailoring code to match the domain or problem at hand, resulting in more meaningful and intuitive expressions.
  3. Infix functions follow precedence rules, with lower precedence than traditional operators like arithmetic and range operators, yet higher than boolean operators and is- or in-checks. Understanding this is crucial for writing correct expressions.
  4. In Kotlin, infix functions simplify code by eliminating explicit dot notation and parentheses, resulting in concise and understandable code. This reduction in visual noise and cognitive load enhances overall code clarity.