Infix functions en Kotlin

Imagina que tienes el siguiente modelo para representar una carta de Póker:

enum class Suit {  
    HEARTS,
    SPADES,
    CLUBS,
    DIAMONDS
}

enum class Rank {  
    TWO, THREE, FOUR, FIVE,
    SIX, SEVEN, EIGHT, NINE,
    TEN, JACK, QUEEN, KING, ACE    
}

data class Card(val rank: Rank, val suit: Suit)  

Es un modelo muy sencillo, se compone de tres partes diferenciadas:

  • Suit. Representa el palo de la carta (corazones, diamantes, tréboles o picas).
  • Rank. Indica el valor de la carta (dos, tres, rey, as, etc.).
  • Card. Una clase que contiene tanto el rank cómo el palo de la carta.

Para componer una carta simplemente hay que hacer:

val card = Card(Rank.QUEEN, Suit.HEARTS)  

Cómo la idea es facilitar la creación de una carta vamos a añadir una función llamada of al enumerado Rank:

enum class Rank {  
    TWO, THREE, FOUR, FIVE,
    SIX, SEVEN, EIGHT, NINE,
    TEN, JACK, QUEEN, KING, ACE;

    fun of(suit: Suit) = Card(this, suit)
}

¿Que hace of? Construye una carta a partir del propio Rank y del Suit recibido como parámetro. ¿Qué conseguimos? Añadir semántica a la creación de una carta, ejemplo:

val card = Rank.QUEEN.of(Suit.HEARTS)  

Podemos ir incluso un poco más allá y usar imports estáticos tanto para QUEEN como para HEARTS para conseguir que la creación de la carta sea más cercano al lenguaje natural:

val card = QUEEN.of(HEARTS)  

Mucho mejor ¿no?. Pues aún hay más, vamos a convertir la función of en una infix function. Para ello simplemente hay que añadir la palabra reservada infix al comienzo de la función:

enum class Rank {  
    TWO, THREE, FOUR, FIVE,
    SIX, SEVEN, EIGHT, NINE,
    TEN, JACK, QUEEN, KING, ACE;

    infix fun of(suit: Suit) = Card(this, suit)
}

¿Qué significa ser una infix function? Básicamente poder usarla con notación infix que, a grandes rasgos, es poder utlizar la función como si de un operador aritmético se tratara, es decir, usarla sin necesidad de escribir el punto y los paréntesis.

¿Cómo queda finalmente el uso de la función of? Te adelanto que super conciso:

val card = QUEEN of HEARTS  

Se podría decir que simplemente es syntactic sugar pero la realidad es que también nos ayuda a acercar muchísimo nuestro código al lenguaje natural, haciéndolo mucho más legible y conciso.