Skip to main content

Expresiones infijas en Scala

⏱ Dedicación recomendada: 0 minutos
Esto considera el contenido visible y relevante, e ignora texto colapsado o marcado como opcional.


r8vnhill/scala-dibs

Luego de haber explorado las expresiones infijas en Kotlin, su sintaxis y sus restricciones, es natural preguntarse cómo se comporta esta idea en otros lenguajes que también promueven la expresividad y la composición fluida de código. En esta lección, veremos cómo Scala —un lenguaje fuertemente influenciado por la programación funcional y orientada a construir DSLs— adopta y extiende el concepto de expresiones infijas con mucha más libertad que Kotlin.

En particular, compararemos las capacidades de ambos lenguajes y pondremos atención a una serie de diferencias clave:

  • En Scala, no es necesario marcar una función como infija: cualquier método con un solo argumento puede usarse como tal.
  • Se permite utilizar símbolos arbitrarios como nombre de método, lo que posibilita la creación de operadores personalizados.
  • No hay restricciones en cuanto al número de parámetros o el uso de valores por defecto para que una función pueda invocarse en forma infija.
  • Scala permite encadenar múltiples operaciones infijas sin paréntesis adicionales, lo que facilita la escritura de código fluido en DSLs.

Estas diferencias hacen que Scala sea un lenguaje más permisivo —y también más propenso a abusos— en lo que respecta al uso de expresiones infijas. A lo largo de esta lección, veremos ejemplos comparativos que ilustran lo que sí puedes hacer en Scala pero no en Kotlin, y discutiremos cuándo esta expresividad adicional es útil y cuándo puede jugar en contra de la claridad del código.

✅ ¿Qué se puede hacer en Scala?

Scala permite que cualquier método con un solo parámetro sea invocado en forma infija, sin necesidad de declarar el método como infix (palabra clave que no existe en Scala). Esto incluye tanto métodos miembros como métodos de extensión (usando implicit class o extension en Scala 3).

🧩 Ejemplo 1: Método miembro como infijo en una biblioteca de IA

Supongamos que estás desarrollando una biblioteca de simulación para juegos o entornos de inteligencia artificial, y deseas ofrecer una API expresiva para modelar interacciones entre entidades. Una de esas entidades podría ser un Robot, que puede realizar acciones sobre un objetivo.

class Robot(val name: String) {
def attacks(target: String): String = s"$name attacks $target"
}

val robot = new Robot("HAL9000")

// Llamada tradicional
robot.attacks("Dave")

// Llamada infija
robot attacks "Dave"

Al exponer el método attacks en forma infija, permites que el usuario de tu biblioteca escriba código más declarativo y legible, como si se tratara de un lenguaje específico del dominio (DSL). Esto resulta particularmente útil en bibliotecas diseñadas para scripting de comportamientos o simulaciones, donde la claridad de la intención es clave.

✅ En Scala, no necesitas usar una palabra clave especial para habilitar la notación infija.
🟣 Esto contrasta con Kotlin, donde solo funciones declaradas explícitamente como infix pueden usarse de esta forma.

Este patrón también se puede aplicar a bibliotecas de validación, motores de reglas o generadores de pruebas, donde los métodos infijos hacen que las reglas se lean como frases naturales:

"username" shouldBeValid
user mustHave "email"
order totalShouldBeGreaterThan 100

Así, Scala permite a quienes diseñan bibliotecas ofrecer APIs que no solo funcionan bien, sino que también se leen bien, un objetivo esencial en herramientas orientadas a usuarios técnicos y no técnicos por igual.

Ejemplo 2: Métodos definidos en objetos o como extensiones

extension (username: String)
def shouldHaveMinimumLength(length: Int): Boolean =
username.length >= length

// Uso infijo
"leif" shouldHaveMinimumLength 4

🟢 Esta capacidad de extender tipos existentes con métodos infijos es muy similar a Kotlin, pero en Scala no hay restricciones como “solo un parámetro y sin valores por defecto” para usarse en notación infija.


🚫 ¿Qué NO se puede hacer en Kotlin pero SÍ en Scala?

Scala permite incluso usar cualquier símbolo como nombre de método, lo que permite definir operadores personalizados con nombres simbólicos:

Ejemplo 3: Operador personalizado con símbolo

class Vector2(val x: Int, val y: Int) {
def +(other: Vector2): Vector2 =
new Vector2(x + other.x, y + other.y)
}

val a = new Vector2(1, 2)
val b = new Vector2(3, 4)

val c = a + b // Usando operador + como infijo

⛔ En Kotlin, solo se pueden sobrecargar un conjunto limitado de operadores predefinidos (+, *, ==, etc.) mediante palabras clave (operator fun).
✅ En Scala, puedes definir cualquier operador simbólico como infijo, lo cual no es posible en Kotlin.


⚖️ Precedencia de operadores en Scala

Al igual que en Kotlin, la precedencia puede causar ambigüedad en expresiones infijas. Pero en Scala, la precedencia está determinada por el primer carácter del nombre del método. Por ejemplo:

val result = 1 + 2 * 3 // * tiene mayor precedencia que +

⚠️ Si defines un método simbólico con un carácter poco convencional (como ?: o !!), podría tener una precedencia confusa para quien lee el código. En Kotlin, no puedes crear nombres de función como símbolos arbitrarios, por lo que este problema no se presenta.


✨ Expresiones más expresivas con múltiples operadores

En Scala puedes combinar infijos en cadena, lo cual puede hacer el código más legible en algunos casos:

val result = "username" shouldHaveMinimumLength 5 shouldBe true

Esto es posible gracias a que las funciones pueden devolver cualquier tipo (incluyendo el objeto original), permitiendo encadenamiento fluido. Este estilo es común en librerías como ScalaTest o Specs2, similares a Kotest.


📌 Conclusión Comparativa

CaracterísticaKotlinScala
¿Requiere palabra clave para infijo?infix❌ No
¿Permite símbolos como nombres de métodos?❌ No✅ Sí
¿Puede ser cualquier método?❌ Solo miembro o extensión✅ Cualquier método
¿Permite más de un parámetro?❌ No✅ Sí
¿Permite métodos infijos definidos globalmente?❌ No✅ Con extension u implicit
¿Encadenamiento fluido natural?✅ Con retorno de this✅ Muy común

Beneficios

  • Scala permite un uso más libre y expresivo de notación infija.
  • Es posible definir operadores personalizados simbólicos, como <<<, ::: o -->.
  • Las expresiones infijas no tienen restricciones en número de parámetros.

Limitaciones

  • La mayor flexibilidad puede generar ambigüedad o abuso, haciendo el código más difícil de leer si no se sigue una convención clara.
  • Las reglas de precedencia simbólica pueden ser confusas para personas nuevas en Scala.