blog de ezamudio

Operadores en Ceylon

El capítulo 6 de la especificación de Ceylon trata de los operadores. Recientemente he estado implementando algunos de estos para el compilador de Ceylon a Javascript y me doy cuenta de que realmente son bastante convenientes, y pues quiero compartir algunas de sus peculiaridades, ya que algunos caben dentro de lo que muchos llaman "azúcar sintáctica".

Los más básicos no son nada extraños; por ejemplo para obtener un miembro de un objeto, simplemente es objeto.miembro; una invocación (a función o método) es con paréntesis, si van a usar argumentos posicionales: f() o f(a,b,c); pero si van a usar argumentos con nombre (cosa que se puede hacer cuando la definición de la función o método tiene argumentos con valores por default y simplemente se los quieren saltar), entonces usan llaves: f{a=1;b="2";}.

La asignación a variables (ojo: variables, no valores inmutables) es como en Pascal, con := pero hay un par de variantes interesantes: en vez de hacer var:=var.f, pueden abreviarlo como var.=f. Y en vez de hacer var:=var.f(x), pueden escribir var.=f(x).

Hola Ceylon, adiós NullPointerException

Todo programador que haya hecho aunque sea la más pequeña aplicación en Java, se ha topado en algún momento con la odiosa NullPointerException. Una excepción que sólo ocurre en tiempo de ejecución, cuando resulta que nuestro código invoca un método o quiere obtener un miembro de un objeto que realmente apunta a null. Y puede ocurrir por cosas tan simples como esto:

String x = "hola";
//algunas líneas más abajo...
if (cualquierCosa) { hola = null; }
//y otras líneas más abajo
int largo = x.length();

El código compila perfectamente. Es más, esto es código que compila sin darnos ningún error, ni advertencia, ni nada:

String x = null;
x.length();

Y uno se pone a pensar... es tan difícil que el compilador se diera cuenta que tengo una variable que apunta a null, y en la siguiente línea estoy invocando un método sobre ese null??????; pero pues así funciona Java. Y si lo anterior es posible, por supuesto puede ocurrir dentro de cualquiera de nuestros métodos que esperan recibir un objeto.

Eficiencia en el uso de memoria en Java

En la lista de desarrollo de Ceylon postearon esta liga a los slides de una presentación de IBM:

http://domino.research.ibm.com/comm/research_people.nsf/pages/sevitsky.pubs.html/$FILE/oopsla08%20memory-efficient%20java%20slides.pdf

Está bastante interesante, desmitifica varias creencias muy comunes acerca de distintos diseños y cómo afectan el uso de memoria, por el lado del tamaño de objetos individuales, tamaño de colecciones en contraste con su funcionalidad, costo de reutilización vs. creación de objetos temporales, etc.

Un simple ejemplo: SimpleDateFormat es un objeto que parece muy simple pero es carísima su creación, está diseñado para ser utilizado varias veces, pero como muchos deben saber, no es thread-safe, por lo cual hay que ser cuidadoso con el reuso.

Le dedican una buena parte a las colecciones de Java, revisando alternativas y proponiendo algunas soluciones; otra parte importante es el ciclo de vida de los objetos. Está algo larga pero realmente muy recomendable.

Tipos en Ceylon: Un sistema de tipos con sentido

Para mi primer post acerca de Ceylon, quiero hablar un poco acerca del sistema de tipos. Una de las metas de Ceylon es la legibilidad del código; otra es tener un sistema de tipos que sea sencillo pero a la vez poderoso (Ceylon es un lenguaje de tipado estático). A continuación pretendo demostrar cómo estos dos objetivos se unen, dando como resultado código más legible, con un ejemplo sencillo: una lista heterogénea (es decir, que contiene elementos de distintos tipos). Veamos el ejemplo en un par de lenguajes de tipado estático, incluso en algunos de tipado dinámico. Primero obviamente en Java:

List<Object> list = Arrays.asList(new Object[]{ 0, "uno", 2, "tres", 4, "cinco" });
for (Object elem : list) {
  if (elem instanceof String) {
    //Para hacer algo con el string requerimos un cast
    String minusc = ((String)elem).toLowerCase();
    System.out.println(minusc);
  } else if (elem instanceof Number) {
    //Igual aqui
    int doble = 2 * ((Number)elem).intValue();
    System.out.println(doble);
  }
}

ScalaSQL: Interfaz sencilla para JDBC desde Scala

Desde hace tiempo que Groovy es mi lenguaje favorito para hacer scripts que a veces necesito para interactuar con bases de datos (algunos reportes o modificar ciertos datos, procesamiento por lotes, etc).

Son principalmente dos razones por las que me gusta tanto usar Groovy para este tipo de scripts:

  1. Tengo a mi disposición todo un arsenal de componentes de Java (simplemente con el JDK tengo un montón de cosas) y además todo lo que me ofrece Groovy como lenguaje, encima del JDK de Java (closures, comprehensión de listas, etc).
  2. El componente groovy.sql.Sql me permite interactuar con bases de datos de manera muy sencilla.

En Scala aún no hay un componente similar. Y aunque lo hubiera, no usaría Scala para scripting (ya he escrito al respecto anteriormente). Pero creo que sí hace falta. Si bien existe el hiperútil componente JdbcTemplate de Spring, para el cual además ya existen unas adiciones para Scala (junto con otras cosas de bean factories) en el proyecto ScalaPrimavera, no siempre es posible o deseable comenzar a depender de Spring.

Así que me propuse desarrollar un componente similar al Sql de Groovy, con algunas cosas adicionales que me han resultado muy útiles de JdbcTemplate, con la finalidad de usarlo en aplicaciones Scala, de modo que debe ser seguro su uso en ambientes multi-hilo, debe tener buen performance, debe manejar bien la transaccionalidad y sobre todo debe ser sencillo de usar.

Primeras impresiones de Ceylon

Como bien saben, hace un par de días contamos con la presencia de Gavin King en las Opentalks, hablando de Ceylon, un nuevo lenguaje de programación que en el que ya lleva cerca de 3 años trabajando. Es un proyecto prioritario dentro de RedHat, pues la intención es tener un nuevo lenguaje de nivel enterprise que sustituya a Java.

Esto no es una reseña del evento; quiero enfocarme a hablar del lenguaje Ceylon, algunas de mis impresiones en este primer contacto que tuve (porque la verdad, no había tenido tiempo de meterme a fondo, más allá de ver aquellos slides que se habían filtrado hace unos meses de una conferencia en China o no sé dónde). He estado pensando acerca de si es mejor hacer una comparativa con otros lenguajes o simplemente hablar de las características de Ceylon sin hablar de ningún otro lenguaje, más que acaso Java, ya que finalmente será un lenguaje que funciona sobre la JVM. Y pues creo que habrá momentos para hacer comparaciones y otros donde es mejor sólo hablar de Ceylon.

Razón de ser

Ceylon surge por razones muy similares a las que han salido otros lenguajes para JVM: Java está evolucionando muy lentamente, se ha vuelto más complicado cada vez, hay que escribir demasiado código para realizar tareas simples, etc. Pero a diferencia de otros lenguajes, la intención de Ceylon es tener adopción a nivel enterprise; es un lenguaje pensado para hacer sistemas grandes con equipos de desarrollo grandes (varios integrantes trabajando sobre una misma base de código, etc). Una consideración importante en el diseño de Ceylon es la legibilidad, tomando en cuenta que en desarrollos grandes, un programador generalmente pasa más tiempo leyendo código ajeno (y propio) que escribiendo código. Por eso es que la legibilidad es una característica muy importante.

RatPack: Servicios REST fácil y rápido

Si alguna vez han tenido que implementar un servicio web usando REST, sabrán que hay muchas opciones para hacerlo. Spring tiene facilidades para implementarlos, hay estándares para realizarlos, y por supuesto hay una gran cantidad de frameworks que pueden estar dedicados a implementar servicios de este tipo o que son para aplicaciones web pero además pueden usarse para implementar servicios REST.

Una opción muy sencilla para REST es RatPack, un framework bastante ligero para hacer servicios REST como scripts en Groovy.

Con RatPack, simplemente definimos los servicios que queremos implementar, en un script de Groovy, y el framework se encarga de lo demás: el servicio se ejecutará como un servlet dentro de Jetty, despachando las peticiones HTTP a los URL's que nosotros hayamos definido.

Los scripts son muy sencillos. Un ejemplo de "hola mundo" en RatPack:

get('/') {
  "Hola, Mundo!"
}

El poder de Either en Scala

Hace tiempo escribí acerca de la versatilidad que nos da el usar Option en Scala, cuando se puede manejar un valor que podría ser nulo.

Esto es muy útil por ejemplo para un método de login: pasamos usuario y password, y obtenemos un Usuario, siempre y cuando exista el usuario con ese nombre y su password sea correcto. Entonces podemos implementar el método de estar forma:

def login(username:String, password:String):Option[Usuario]={
  val user = //Buscamos el usuario en la base de datos
  if (user != null && passwordEsValido) Some(user)
  else None
}

Entonces cuando invocamos el método login, ya no tenemos que validar contra null en un if para proceder de una forma, y presentar un error en el else; en vez de eso podemos hacer distintas funciones:

def continuar(user:Usuario)=//esto lo invocaremos si el login estuvo OK
def error()=//Esto lo invocaremos si el login falla

//Aquí viene lo bonito de usar Option:
//Esta línea de código expresa muy claramente lo que hay que hacer
login("username", "password") map continuar orElse error

ScalaQuery: Un DSL para acceso a base de datos en Scala

La manera más básica o primitiva de interactuar con una base de datos en Java es por medio de JDBC. Esto por supuesto se puede hacer también en Scala, Groovy o cualquier otro lenguaje para la JVM, pero al usar JDBC se tiene que programar en estilo Java por la manera en que fue diseñado.

En Scala existe una alternativa interesante: ScalaQuery. Lo que esta biblioteca nos permite hacer es realizar queries con código Scala, con un margen de error mucho menor, ya que se aprovecha el tipado estático del lenguaje de una forma que incluso en Java no se hace con JDBC.

La mejor manera de ilustrar su uso es con un ejemplo sencillo. Supongamos que tenemos una tabla, definida así en SQL:

CREATE TABLE ejemplo(
  clave     SERIAL PRIMARY KEY, --autoincrementada
  nombre    VARCHAR(80) NOT NULL,
  apellidos VARCHAR(80) NULL,
  fecha_nac DATE NOT NULL,
  ultimo_acceso TIMESTAMP NULL,
  entero    INT NULL,
  saldo     NUMERIC(10,4) NOT NULL
)

Disruptor: una nueva estructura de datos

Algunos de ustedes tal vez conozcan el esquema productor-consumidor; es un escenario simple de concurrencia: un hilo o proceso está creando datos para procesar, los cuales tienen que ser procesados por otro hilo o proceso.

El productor puede estar generando estos datos porque está leyéndolos de un socket, o de algún sensor conectado a la computadora (temperatura, teclado, ratón, etc), o vienen de base de datos, etc. La cosa es que se dedica exclusivamente a producir estos datos, no puede procesarlos porque entonces puede perderse de algunos de los datos que vienen de la fuente, por estar procesando lo que tiene. Por eso hay un consumidor de estos datos, que debe procesarlos en un hilo aparte.

La comunicación entre productor y consumidor por lo general se resuelve utilizando una cola: una estructura de datos tipo FIFO en donde el productor va colocando los datos que produce y el consumidor va tomando datos para procesarlos.

Distribuir contenido