XTend (intro al lenguaje)

Introducción

Apunte de Xtend para programadores objetosos (complementa esta página).

XTend es un lenguaje de programación orientado a objetos, parte de la comunidad de proyectos de Eclipse. Por esto, por ahora, resulta dificil trabajar en xtend con otro IDE que no sea el eclipse (en realidad es posible, pero dificil). Ante todo, el link al sitio oficial

http://www.eclipse.org/xtend/

Ahí van a encontrar la documentación más actualizada y completa. Acá simplemente pretendemos hacer una introducción y relacionarlo con lenguajes que ustedes ya conocen de cursadas anteriores.

Características Generales

Xtend es un lenguaje:

  • Con tipado estático: es decir que las variables tienen un tipo, y que el compilador, en "tiempo de compilación" checkea la validez de los tipos del programa. Por ejemplo que si un método espera un Integer como parámetro, no pueda yo estar pasándole un String. El término correcto para esta característica es checkeos en tiempo de compilación. Y debería resultarles conocido de lenguajes como Java.
  • Inferencia de tipo: a diferencia de Java, no hace falta declarar los tipos "siempre". El lenguaje tiene un mecanismo "inteligente" que los infiere en ciertas condiciones. Esto va a hacer que nuestro código sea bastante más conciso que en java. Más tirando a parecerse a código "smalltalk", si se quiere.
  • Con sintaxis concisa: a diferencia de java también, varios elementos de la sintaxis son opcionales, como los puntos y coma, y a veces paréntesis. Con lo cual el código se reduce bastante.
  • Con elementos de lenguajes modernos: como bloques de código, multiple dispatch, etc. De nuevo, esto reduce la cantidad de código que escribimos.

En general, para el uso que le vamos a dar en la materia, van a ver que Xtend es muy parecido a Java (en cuanto a que sigue las reglas más importantes/generales de java), pero con una sintaxis mucho más amigable.

Compatibilidad con Java

Compatibilidad con Java

Xtend es un lenguaje 100% compatible con java:

  • código xtend puede usar código java
  • código java puede usar código xtend

Esto es porque, en realidad el "compilador" de xtend, lo que hace es generar código Java a partir de nuestro código xtend.

Una vez que se generó el código Java, se sigue la ejecución de cualquier programa Java.

               .xtend      ->    .java     ->  .class

Características Específicas

Veamos algunas características en detalle

Variables y Valores

Existen dos tipos de "variables", o mejor dicho "referencias":

  • Variables: son referencias que pueden inicializarse apuntando a un objeto, y luego reasignarse a otro. Justamente "variables"
  • Valores: referencias que nacen apuntando a un valor y no pueden ser modificadas para apuntar a otro objeto. Serían como "constantes"

La sintaxis es:

Ojo ! no confundir el hecho de que no se pueda modificar la "referencia" de la mutabilidad/inmutabilidad del objeto al que apunta. Puedo tener un "val" apuntando a una colección, que es mutable.

La referencia es inmutable (no se puede modificar), pero el objeto es mutable (se puede modificar), en este caso.

Inferencia del tipo de las referencias

La declaración de una variable puede omitir especificar el tipo de la misma, ya que xtend analiza el código, por ejemplo el valor al que estamos asignándola, e infiere el tipo.

Ejemplo de equivalencias

val n = 23

val s = "hola"

var Collection<String> strings = new ArrayList<String>()

val Integer n = 23

val String s = "hola"

var strings = new ArrayList<String>()

Literales de Colecciones

Existe una sintaxis especifica para crear colecciones con sus elementos, sin tener que escribir el código que instancia un objeto y luego envía el mensaje "add(..)", etc.

Clases

La mecánica de las clases en xtend es igual que en Java. La diferencia es que la sintaxis es mucho más concisa.

Veamos un ejemplo en java

En xtend esto se puede escribir así

Acá vemos:

  • En general no hace falta especificar la visibilidad de las cosas (public, private, etc), porque xtend ya tiene buenos "defaults". Entonces si uno no especifica nada:
    • clases: son public
    • variables de instance: private
    • métodos: public
  • Métodos:
    • se declaran con def
    • No hace falta declarar el tipo de retorno (ej: "getEnergia") ya que lo infiere mirando el código dentro, el tipo del valor que retornamos
    • No hace falta escribir return, el valor de retorno de un método será la última linea (en realidad se banca expresiones como if's que retornen cosas en ambas ramas)

@Accessors

El ejemplo anterior se puede simplificar aún más. En java es bastante común que una clase tenga una "propiedad", es decir un par de métodos "getter" y "setter" que retornan una variable de instancia y la alteran respectivamente. Esto es engorroso porque tenemos que escribir la variable de instancia y ambos métodos. Para evitar esta tarea tediosa, xtend tiene una annotation llamada @Accessors, y nos permite sólo escribir la variable de instancia.

El getter y el setter los genera automáticamente. Nuestra clase quedaría ahora así:

De hecho este es el código que generará:

También podemos utilizar la annotation @Accesors en la clase, con lo que estamos definiendo getters y setters para todos los atributos de esa clase.

Shortcut para acceder a propiedades

Cuando usamos un objeto que tiene propiedades (par getter y setter), podemos cambiar un poco la sintaxis para que se vea más simple.

Ejemplo, en lugar de esto

Podemos hacer esto:

O sea una propiedad se puede acceder así

    objeto.propiedad

Y modificar así

    objeto.propiedad = valor

Ojo! si bien parece que estamos accediendo diréctamente a la variable de instancia, no es así. Xtend simplemente traduce esa sintaxis a la anterior. Es decir que en ambos casos estamos igualmente llamando al getter y al setter. Es sólo un chiche sintáctico (evitamos los paréntesis y los prefijos "get" y "set".

Eliminando Paréntesis

Incluso, cuando un método o constructor no recibe parámetros podemos evitar escribir los paréntesis.

Constructores

Son casi iguales a los de Java, sólo que no tienen el nombre de la clase sino la palabra reservada new. Ejemplo, lo que en Java se escribía así:

En xtend se escribe:

Nótese que por default los constructores también son public, así que no hace falta declararlo (por si no se entendió, en este ejemplo tenemos dos constructores, y uno delega en el otro pasándo el valor "fijo" default de 100 puntos de energia).

Sobrescritura de métodos

Cuando extendemos una clase y queremos sobrescribir un método, no podemos definirlo con def sino que tenemos que usar la palabra reservada override

Nota: existe el super igual que en java, para invocar un método de la superclase.

Archivos y clases

A diferencia de Java, en un archivo xtend se puede declarar más de una clase y/o interfaces. Esto es ya que, con todas las cosas que vimos la sintaxis es mucho más concisa, y el código en general es más "corto". Con lo cual, se presta a escribir clases chiquitas, y tener un archivo por clase, a veces, tiende a ser molesto.

Ejemplo

Colecciones y Bloques

Xtend trabaja con las mismas clases de colecciones que ya vienen con Java, por ejempleo java.util.Collection, java.util.List, ArrayList, LinkedList, Map, etc.

Sin embargo, a través de un mecanismo más complejo que no vamos a ver en la materia (llamado extension methods), cuando usamos estas colecciones desde código xtend, vamos a ver que tienen más métodos ! Y son métodos bastante piolas :)

Asumiendo que todos usaron Smalltalk/Wollok en otra materia, van a encontrar muchos métodos que sí estaban en esas colecciones, pero no en Java. Estos métodos en general reciben bloques (o también llamados closures) como parámetro. Xtend soporta bloques. Veamos ejemplos:

El método filter espera recibir un bloque de un único parámetro que retorna un booleano, indicando si el elemento cumple con la codición.

Acá vemos que la sintaxis de bloques en xtend es

   [ tipo parametro1, tipo parametro2, ...   |    código ]

El ejemplo anterior obtiene otra colección que tendrá sólo los números positivos de la original. Incluso, utilizando la inferencia de tipos, podemos evitar declarar que el parámetro del bloque es de tipo "int", ya que la colección ya sabe que es de tipo Collection<int>, entonces solito el filter ya espera un bloque de tipo (int)=>boolean y nos queda así

Incluso, cuando un método recibe un único parámetro de tipo bloque, podemos evitar los paréntesis, quedando así

Veamos otro ejemplo con objetos complejos, como nuestras Golondrinas

Podemos reducir aún más el código, utilizando la idea del parámetro "implícito" o receptor implícito it. En xtend, además del this que referencia a la instancia actual, existe otra variable similar llamada it. Este it, en el caso de un bloque representará el parámetro, siempre y cuando sea un bloque con un único parámetro. Así que podemos evitar ponerle nombre al parámetro "golondrina" y en su lugar usar "it".

Quedaría así:

Podemos reducir aún más el código, ya que el it se puede omitir, y dentro del bloque todos los mensajes serán enviados a it, es decir al parámetro. Así que terminamos con esta forma:

Todas expresiones equivalentes, siendo esta última la más concisa. Bastante parecido a Smalltalk/Wollok, no? ;)

Otros métodos de colecciones

Ahora que ya vimos la mecánica, vamos a pasar más rápido otros métodos útiles de las colecciones

O bien:

recolecta las energías de cada una de las golondrinas (transforma una colección de golondrinas en una colección de números que son la energía de cada golondrina).

ForEach

Permite aplicar una serie de operaciones con efecto a un conjunto de objetos

O bien

No retorna nada.

forAll

Permite conocer si todos los elementos de una colección cumplen una condición

Retorna true sólo si el bloque se cumple para todos los elementos