Una perspectiva del uso de tuplas en Groovy!

El uso de Tuplas en Groovy me parecía algo innecesario, ya que el lenguaje cuenta con listas muy agradables y un método que permite hacerlas inmutables.

def lista1 = ["Rodrigo", 30]
lista1.collect{ it }

def lista2 = ["Rodrigo", 30].asImmutable()
println(lista2.getClass())
lista2[0] = 'Rambo!'

/**
class java.util.Collections$UnmodifiableRandomAccessList
...
java.lang.UnsupportedOperationException
        at java.util.Collections$UnmodifiableList.set(Collections...
*/

Y porque hacer algo como lo anterior si Groovy cuenta con tuplas (groovy.lang.Tuple).

def tuple = new Tuple("Rodrigo", 30)
println(tuple)
java.util.Collections.reverse(tuple)

/**
[Rodrigo, 30]
...
java.lang.UnsupportedOperationException
        at java.util.AbstractList.set(AbstractList
*/

No se si sea mejor usar listas inmutables en lugar de tuplas, pero una queja es que no se puede hacer una tupla como lo haría con una lista ([...]), como lo siguiente.

def tuple = (“Rodrigo”, 30)

/** expecting ')', found ',' at ... */

No esperen que estoy diciendo en Groovy sí se pueden definir tuplas con esa sintaxis pero el objetivo no es que trabajen como un conjunto ordenado de datos inmutables, si no como un medio de asignación de valores.

/*
def nombre = "Rodrigo"
def edad = 30
*/

def (nombre, edad) = ["Rodigo", 30]
println("${nombre} tiene ${edad} años")

/** Rodigo tiene 30 años */

Pero bueno eso no es algo que impresione mucho verdad, pero podría ser muy útil en algún caso similar al siguiente.

def m = "foobarfoo" =~ /o(b.*r)f/
def (sonido, lugar) = m[0]
println("El perro ladro '${sonido}' en un ${lugar} al ver a ...")

/** El perro ladro 'obarf' en un bar al ver a ... */

Otra cosa interesante es el operados '_', que me trae luego luego a la mente el Wild-cards de Haskell. Aun que Groovy se inspira/basa en otros lenguajes.

def (paterno, _, nombre) = "Salado Anaya Rodrigo".split()
println("Nombre: ${nombre}, Apellido paterno: ${paterno}")

/** Nombre: Rodrigo, Apellido paterno: Salado */

Otra cosa en las que estuve jugando fue no solo pensar en asignar objetos. Veamos que pasa con las funciones anónimas/Closures.

def (d, e) = [
    { x, y -> x - y },
    { x, y -> x + y }  
]
assert d(5, 1) == 4
assert e(2, 3) == 5

Y que pasa cunado usamos @groovy.transform.TypeChecked y esta dando lata que no puede inferir el tipo. Lo que se puede hacer es definir el tipo en cada caso.

def (String a, int b) = ["Rodrigo", 30]

Ya para concluir que sucede con los null. Groovy es muy raro :S

/** Usando:
$ groovy --version
Groovy Version: 2.1.2 JVM: 1.7.0_11 Vendor: Oracle Corporation OS: Mac OS X
*/

def (a, b, c) = ["Rodrigo", 30]
println("a: ${a}, b: ${b}, c: ${c}")
/** a: Rodrigo, b: 30, c: null */

def (a, b, c) = ["Rodrigo", 30, null]
println("a: ${a}, b: ${b}, c: ${c}")
/** a: Rodrigo, b: 30, c: null */

def (String a, b, c) = ["Rodrigo", 30, null]
println("a: ${a}, b: ${b}, c: ${c}")
/** a: Rodrigo, b: 30, c: null */

//Que onda con esto alguien me lo explica?
def (String a, int b, c) = ["Rodrigo", 30, null]
println("a: ${a}, b: ${b}, c: ${c}")
/** org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'null' with class 'null' to class 'int'. Try 'java.lang.Integer' instead */

def (String a, b, int c) = ["Rodrigo", null, 30]
println("a: ${a}, b: ${b}, c: ${c}")
/** a: Rodrigo, b: null, c: 30*/

En fin el ultimo punto estaba de más, pues gracias por el tiempo que se tomaron y a la comunidad por el espacio.
Mucho de los ejemplos se podría considerar plagio, pero me tome la molestia de cambiar muchas de las letritas. Y por supuesto estoy ávido de aprender de ustedes con sus comentarios o la forma que gusten.

Referencias:
http://es.wikipedia.org/wiki/Tupla
http://groovy.codehaus.org/Multiple+Assignment+Proposal
http://groovy.codehaus.org/Multiple+Assignment
http://groovy.329449.n5.nabble.com/Why-has-groovy-no-built-in-tuple-supp...
http://mrhaki.blogspot.mx/2011/04/groovy-goodness-tuple-constructor.html
http://groovy.codeplex.com/wikipage?title=Blog02#11
http://almaer.com/blog/tuples-and-globals-in-groovy
http://groovy.codehaus.org/Collections
http://groovy.codehaus.org/Regular+Expressions

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de benek

Muy buen post! //Que onda

Muy buen post!

//Que onda con esto alguien me lo explica?
def (String a, int b, c) = ["Rodrigo", 30, null]
println("a: ${a}, b: ${b}, c: ${c}")
/** org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'null' with class 'null' to class 'int'. Try 'java.lang.Integer' instead */

No hay mucho detalle en la página que describe la asignación múltiple, pero haciendo un par de pruebas es notorio que una vez declarando un tipo, las variables siguientes tomarán ese tipo específico, a menos de que se declare otro.

def (int i, String s, t, u, v) = [10, 'foo', 1, 1, 1]

println i.class
println s.class
println t.class
println u.class
println v.class

class java.lang.Integer
class java.lang.String
class java.lang.String
class java.lang.String
class java.lang.String

El tipo de las variables se mantiene a partir de String s y aunque se le asignen valores de otro tipo (en el caso de t, u, v que reciben un int) serán convertidos hacia el tipo String.

Imagen de rodrigo salado anaya

Re: El tipo de las variables se mantiene ...

Orale muy buena observación Benek, gracias también me aventé un par de pruebas y estoy de acuerdo con lo que dices. Gracias y saludos mi estimado. : )

Imagen de ezamudio

tuplas...

Lo que no entiendo es, qué tanto sentido tienen las tuplas de esta forma en un lenguaje de tipado dinámico? Más allá de servir como conveniencia para multi-asignaciones...

Imagen de Shadonwk

Exacto, programar con tipos

Exacto, programar con tipos de variables es muy Java, a Groovy eso no le importa... pero se puede.

Imagen de rodrigo salado anaya

Re: tuplas...

Tal ves pudieran ser útiles cuando se usa la notación @TypeChecked con tipos más complejos que un String o Integer.

Imagen de ezamudio

Sólo así

En sistemas de tipado estático, una tupla es un contenedor indexado donde cada elemento puede tener un tipo distinto y se conoce en tiempo de compilación, de tal modo que sabes que tupla[0] es un entero y tupla[1] es un String, etc.

En Groovy pueden tener la misma utilidad que tendrían en Java si se usan tipos, y obviamente pueden servir para interoperabilidad. Un uso muy común de tuplas es para poder definir métodos o funciones que retornan dos o más valores. Pueden también ser útiles si se usan en conjunto con un ORM simple, o alguna herramienta para interactuar con una base de datos, que devuelva tuplas como resultado de una consulta, y es un mapeo directo de las tuplas de una tabla en una base de datos relacional a las tuplas del lenguaje que se está usando.

Imagen de rodrigo salado anaya

Re: Sólo así

Incluso se me ocurre que para algún tipo de proveedor de mensajería, en Groovy podría servir ya que el consumidor del mensaje podría estar seguro de los tipos que esta recibiendo, añadiendo el plus de la inmutabilidad.

Imagen de benek

Ah sí? Pues en Scala puedes

Ah sí? Pues en Scala puedes usar elegantemente hasta 22 tuplas!!!! >> https://github.com/scala/scala/blob/v2.10.1/src/library/scala/Tuple22.scala

Imagen de ezamudio

jajajaj

pinches tuplas de Scala jajajaj son un parche horrendo. Pero no es "hasta 22 tuplas", realmente es tuplas de hasta 22 elementos. Igual que puedes tener funciones hasta de 22 parámetros.

Ahí sí la verdad mis respetos para Gavin, el diseño que se aventó de tuplas en Ceylon es una chingonería y sólo es posible gracias a los tipos unión (y al sistema de tipos de Ceylon en general). Pueden soportar cualquier cantidad de elementos, ya que es simplemente una definición recursiva: Tuple<out Element, out First, out Rest> given First satisfies Element given Rest satisfies Element[]. Y al agregar un poco de azúcar sintáctica entonces puedes definir por ejemplo una tupla de 3 elementos simplemente como [Integer,String,Character] (a nivel declaración de tipos) y crear una con una expresión [1, "2", '3']. Lo anterior va a crear una tupla de este tipo:

Tuple<Integer|String|Character, Integer, Tuple<String|Character, String, Tuple<Character, Character, Empty>>>

Cómo funciona? Pues la primera tupla sabe que su primer elemento es tipo Integer, porque eso indica su segundo parámetro de tipo. Su segundo elemento es el primer elemento de la segunda tupla; el primer elemento de la segunda tupla es tipo String y el tercer elemento es el primer elemento de la tercera tupla, que es un Character. Es decir a fin de cuentas es una cadena de tuplas donde cada una sabe el tipo de su primer elemento; obtener elementos por índice no es muy eficiente por el momento, pero para eso ya haremos luego optimizaciones en el código, pero lo importante es que se tiene una definición elegante, simple y poderosa de una tupla fuertemente tipada, aprovechando los tipos unión (y otras cosas, como por ejemplo que la tupla misma satisface la interface Sequential, que es una colección inmutable que no puede estar vacía).

Imagen de benek

Eso está muy chingón, lo

Eso está muy chingón, lo explicó en las #OpenTalks.

Ah, y en Scala sí puedes usar "hasta 22 tuplas", porque hay 22 clases!! jaja

Imagen de ezamudio

no

Lo de las tuplas no lo pudo haber explicado en las opentalks porque todavía no existían... las hizo apenas en Octubre del año pasado.

Imagen de echan

wow .. sin ser avezado en

wow .. sin ser avezado en ceylon por lo que comenta ezamudio las tuplas solo son una lista enlazada. Tecnicamente se puede crear "tuplas" con culquier lenguaje que tengar recursion aunque entre la tupla y la lista hay una pequeña diferencia teorica

https://en.wikipedia.org/wiki/Algebraic_data_type

Imagen de ezamudio

así es

Efectivamente son listas enlazadas, la diferencia es que puedes determinar el tipo de cada elemento de la lista en tiempo de compilación.