Post

Mastering Infix Operators in Swift: Built-In and Custom Operators

Learn about operators in Swift and how to create a custom operator like the forward pipe operator (|>).

Mastering Infix Operators in Swift: Built-In and Custom Operators

Operators in programming languages instruct the compiler or interpreter to perform specific operations on values, known as operands. In Swift, operators handle tasks ranging from basic arithmetic (e.g., +) to custom operations that enhance code clarity and style.

Operators in Swift

Built-In Operators

Swift provides a variety of built-in operators for common operations:

  • Arithmetic Operators: +, -, *, /
  • Comparison Operators: ==, !=, <, >
  • Logical Operators: &&, , !
  • Bitwise Operators: &,, ^, ~

These operators follow standard conventions, making common computations straightforward.

Custom Operators

Swift allows defining custom operators, which are useful for domain-specific or functional programming styles. Custom operators have associated precedence and associativity to determine how they combine with other expressions.

The Forward Pipe Operator (|>)

The forward pipe operator enhances code readability by “piping” a value through a chain of functions. Here’s how to implement it:

1
2
3
4
5
6
7
8
9
10
11
12
// Define precedence and associativity
precedencegroup PipeForward {
    associativity: left
}

// Declare the operator
infix operator |>: PipeForward

// Implement the operator
func |> <T, U>(lhs: T, rhs: (T) -> U) -> U {
    return rhs(lhs)
}

How It Works

When using the operator:

1
let result = value |> function

Swift translates it to:

1
let result = function(value)

This eliminates the need for explicit parentheses or parameter names, making the code more concise.

Chaining Functions in Swift

Swift supports function chaining in several ways, with one common approach being through structs. By returning a new modified self in struct methods, you can create modified values. For example:

1
2
3
4
5
6
7
8
9
10
11
extension Int {
    func increment() -> Int {
        return self + 1
    }

    func square() -> Int {
        return self * self
    }
}

let result = 5.increment().square()

Here, the value 5 is incremented to 6 and then squared to 36. This approach enables clear and expressive chaining.

Using the Forward Pipe Operator for Chaining

To demonstrate, consider these functions:

1
2
3
4
5
6
7
func increment(_ value: Int) -> Int {
    return value + 1
}

func square(_ value: Int) -> Int {
    return value * value
}

With the forward pipe operator:

1
let transformed = 5 |> increment |> square

This translates to:

1
let transformed = square(increment(5))

The operator enhances readability by reflecting the sequence of transformations applied to the value.

Why Parentheses and Parameter Names Aren’t Needed

After defining the precedence group with its associativity, the operator passes the left-hand value as input to the right-hand function, eliminating the need for parentheses and parameter names. This streamlines the syntax.

Comparison: Pipe Operator vs. Method Chaining

Using the forward pipe operator:

1
let transformed = 5 |> increment |> square

Using method chaining:

1
let transformed = 5.increment().square()

Both approaches yield the same result. The forward pipe operator is ideal for standalone functions, while method chaining works well with custom structs or extensions. The choice depends on your coding style.

Conclusion

Swift’s custom operators, like the forward pipe operator (>), enable clean, functional-style code. By reducing parentheses and parameter names, they improve readability and expressiveness. Try using the forward pipe operator in your projects to enhance function chaining and simplify your Swift code!

☕ Support My Work

If you found this post helpful and want to support more content like this, you can buy me a coffee!

Your support helps me continue creating useful articles and tips for fellow developers. Thank you! 🙏

This post is licensed under CC BY 4.0 by the author.