Scala: El lenguaje estático que se siente como dinámico (Bruce Eckel)

Burce Eckel ( el escritor de "Thinking in Java" , "Thinking in C++" y que provee asistencia de desarrollo para Python y Flex, es conferencista y algunos otros etc's más ) escribe este árticulo sobre Scala:

http://www.artima.com/weblogs/viewpost.jsp?thread=328540

Algo que me hace sentir un tanto incómodo es el hecho que al parecer escribe solo sobre lo que ya esta probado como un éxito.

Domix comenta en twitter:

" [...]recuerdo cuando [Bruce Eckel ] se la pasaba promoviendo Flex..."

En fin.

Sobre el articulo mismo hay un par de cosas que me llaman la atención.

1.- Scala no es complejo. Para demostrarlo hace un ejemplo de procesamiento de un archivo que dice que en Java es muy "ceremonioso" contrastandolo con un ejemplo en Scala como sigue:

val fileLines = io.Source.fromFile("Colors.scala").getLines.toList
fileLines.foreach(println)

Lo cual, sinceramente si es muy simple, pero lo que hace mal, es confundier el lenguaje con sus bibliotecas ( yo mismo insisto que un lenguaje es sintaxis + bibliotecas + plataforma ) pero me parece que el ejemplo no demuestra nada.

Lo mismo se puede escribir en Java así:

// In Java using the same library:
for( Iterator e = (Iterator) Source.fromFile("UsingScala.java", "UTF-8").getLines();  e.hasNext() ; ) {
           out.println( e.next() )  
}

Claaro, el truco es usar la mismo biblioteca que usa Scala ( scala.io.Source ) , entonces no demuestra una característica de simpleza del lenguaje sino lo bien que están sus bibliotecas. Hay que admitir sin embargo que leer un archivo en Java es un tanto "ceremonioso" ( aunque no tanto usando la clase Scanner ).

2.- Ejemplo de programación funcional. Se queda corto el ejemplo, pero suponiendo que la idea fuera no espantar a las personas que vean por primera vez esto, aún así el ejemplo que pone se vuelve un tanto ridículo ( en mi opinión claro).

Algo que siempre he a desconcertado un poco de Scala son las distintas formas en las que se puede escribir la misma cosa. No las diferentes maneras en las que se puede escribir algo similar para obtener el mismo resultado ( como un for , un while y recursión para uar un bucle y que si son cosas distintas ) sino literalmente la misma cosa!!

Para un vector de doubles las siguientes seis sentencias son exactamente iguales:

v.foreach((n:Double) => println(n))
v.foreach((n) => println(n))
v.foreach(n => println(n))
v.foreach(println(_))
v.foreach(println)
v foreach println

Esta muy padre tener flexibilidad y todo, pero tener 6 formas de escribir exactamente lo mismo me parece demasiado.

Scala es un lenguaje de programación muy interesante. Hay cosas de su naturaleza híbrida que a veces desconciertan ( o del nuevo paradigma que quieren crear sus promotores: Object-Functional ), pero definitivamente es algo digno de aprenderse y utilizarse.

Veremos si ahora Bruce se dedica a ser promotor de Scala como lo ha sido de otros lenguajes en el pasado, solo espero que sus ejemplos sean mejores.

¿Que opinan?

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 bferro

No es nada malo tener flexibilidad

En casi todos los lenguajes varias de sus construcciones se pueden escribir de varias formas. Eso no debe confundir, una vez que se domina el lenguaje. pero puede ser muy útil para entender el lenguaje cuando se está aprendiendo. Pongo un ejemplo muy sencillo en Java.

class Padre {
   
}
class Hijo extends Padre {
    int attr1;
    Hijo(int attr){
        attr1 = attr;
    }
    void met1() {
        met2();
    }
    void met2() {
        //stuff
    }
   
}

Puede que sea mi objetivo con este código explicar varias cosas: llamada al constructor de la clase base cuando se crea un objeto de clase derivada; acceso a los datos miembros de este objeto en su constructor; acceso a los métodos de este objeto dentro de la propia clase, etc.
Puedo entonces hacer más explícito el código con el objetivo de explicar esas cosas y comienzo entonces a escribir diferentes variantes:
Para hacer evidente el "ciclo" de construcción de un objeto,hago explícito lo que en el código anterior está implícito:

class Padre extends Object {
    Padre() {
        super();
    }
   
}
class Hijo extends Padre {
    int attr1;
    Hijo(int attr){
        super();
        attr1 = attr;
    }
    void met1() {
        met2();
    }
    void met2() {
        //stuff
    }
   
}

Para hacer evidente que en el constructor se modifica el atributo attr1 del objeto que se está construyendo, hago explícito lo que antes estaba implícito (pongo solamente la porción que cambio):

    Hijo(int attr){
        super();
        this.attr1 = attr;
    }

Para evidenciar que met1, aplica met2 sobre el mismo objeto, hago explícito lo que está implícito:

    void met1() {
        this.met2();
    }

Y por tanto tengo diferentes formas de escribir lo mismo y si se entiende no debe confundirnos, una vez que aprendemos el lenguaje. El ejemplo que pone Oscar de Scala tiene que ver mucho con eso:

v.foreach((n:Double) => println(n))
v.foreach((n) => println(n))
v.foreach(n => println(n))
v.foreach(println(_))
v.foreach(println)
v foreach println

Si sigo esas expresiones en orden, lo que estoy haciendo es caminando de una expresión muy explicita a una expresión menos elocuente, aplicando conceptos importantes del lenguaje: funciones de orden superior, inferencia de tipos, place holders, facilidades sintácticas y expresiones postfijas.
En lo personal, me agrada la idea, pero para gustos se han hecho colores.

Imagen de OscarRyz

Si claro, como comentaba en

Si claro, como comentaba en la presentación las cosas son más naturales o más raras dependiendo del planeta de donde vengas.

El punto de los constructores en Java es muy interesante y no se me había ocurrido, sin embargo creo que la incidencia de constructores vs. invocación a métodos ( o funciones ¿como llamarlas en Scala? weno métodos ) es menor en el código.

Pero tienes razón. Yo creo que la flexibilidad es buena, quizá el punto es que simplemente de acepte que es más complejo y ya!.

"Scala es complejo y poderoso". No me parecería malo decirlo.

Creo que si hay una relación entre simpleza y expresividad. Entre más simple es un lenguaje más difícil es expresar las cosas. Entre más complejo es un lenguaje más fácil es por que provee sintaxis casi para cada cosa.

Ejemplo:

case class Persona( nombre: String, apellido: String, edad : Int )
Imagen de java.daba.doo

Es como usar sinonimos

A mi me parece adecuadoque puedas EXPRESARTE de fdiferentes formas cuando codificas, de otra manera es como cuando te refieres a un coche, carro, vehiculo, automovil... que aburrido que tuviera solo una palabra, entonces como Scala y Java y los demas son LENGUAJES es natural que caigan los sinonimos y "oraciones que expresen lo mismo" aunque se vea diferente y si es asi es que no puede aplicar una estructura para cada contexto, es por eso que puedes omitir los parentesis en X caso, puedes omitir el tipo en XX caso y asi con cada ejemplo. Si alguien no entiende tu codigo es porque quien lo hizo no se sabe dar a entender. Un lenguaje es entendible per se (ya no hablemos de si te gusta o no) pero lo que lo hace no entendible es "el que lo domina" ante el que no lo hace. El que lo domina puede escribir una linea que sntetice a 30 (por decirlo) y el que no lo domina simplemente no lo entiende y punto

Como dice @bferro:

si se entiende no debe confundirnos, una vez que aprendemos el lenguaje

un ejemplo mas son las expresiones regulares. Que hay quienes ponen y ponen condiciones y limites y hasta validan al perico antes de otra cosa... hay quienes en 7 caracteres te validaron lo mismo pero insisto, es cosa de quien lo hace

termino citando una frase que me gusto de @OscarRyz cuando presento #Ryz : "En cualquier lenguaje se pueden hacer cochinadas"

Imagen de ezamudio

Groovy

Groovy también tiene varias maneras de expresar eso mismo que ejemplificaron en Scala, tal vez no las 6, aunque honestamente la segunda de esas 6 la considero superflua, sólo son paréntesis en el parámetro, y si nos vamos por ese lado, podemos hacer 500 variantes de lo mismo, poniendo paréntesis en distintos lados. Pero bueno:

v.each { Double n -> println(n) }
v.each { n -> println(n) }
v.each { n -> println n } //paréntesis en métodos con un argumento son opcionales (y en otros casos también)
v.each { println it } //Si no defines parámetros en un closure, tiene uno por default y se llama "it"

Las últimas dos en Scala no veo cómo podrían hacerse en Groovy. Las llaves son necesarias para delinear closures y bloques de código. Y el parámetro que se pasa a println debe ser explícito. Esas dos variantes no me gustan mucho porque no son nada fáciles de entender si no estás familiarizado con algo de programación funcional.

Imagen de OscarRyz

Ahh... yo creí que ibas a

Ahh... yo creí que ibas a decir:

"No se trata des escribir menos líneas de código, sino de expresar más fácilmente tus intenciones - Ryz"

Yo pienso que la sintaxis de los lenguajes de programación debe de ser como las interfaces gráficas de usuario. Deben de ser usables, también deben de verse bien pero deben de ser monótonas y sencillas de usar en el sentido de que deben de tener pocas opciones que el usuario tenga que elegir ( notesé que digo tenga y no pueda ).

Cuando hay muchas opciones el usuario final tiene que decidir la interfaz se vuelve menos eficiente, es por eso que por ejemplo Google Chrome tiene esa interfaz tan simple que resulta más fácil de usar, o los productos Apple son tan intuitivos, todo se hace más o menos igual ( por ejemplo cmd + ; es preferencias en cualquier app ). Algo similar pasa con los lenguajes de programación.

Un ejemplo de mucha eficiencia y monotonía en Scala mismo es la inferencia de tipo. No se debe de pedir al programador que escriba y reescriba el tipo de dato si es obvio ( o en Scala quizá no tan obvio pero inferible ) En este caso hay otra opción que es declararlo explicitamente. Pero hasta ahí tenemos solamente 2 opciones:

val a = 1
val b : Int = 2

Si tuviéramos 6 opciones para escribir exactamente lo mismo ya estaría más complicado elegir alguna.

No estoy encontra de las opciones, para nada, de hecho lo malo está cuando por falta de opciones tienes que escribir siempre de la misma manera, pero tampoco me gusta que haya tantas formas para escribir exactamente lo mismo.

Por otro lado ¿Que opinan del ejemplo de "No es tan ceremoniso como en Java porque..." y que se use una biblioteca del lenguaje ( que como se vió tampoco es tan ceremonioso en Java usando la mismo biblioteca )

Alguién ( creo que fue java.daba.doo ) puso el ejemplo usando Scanner

String fileContent = new Scanner(new FileInputStream("./src/demo/java/Super.java")).useDelimiter("Z").next();

Sin tanta ceremonia.

Scala si es más poderoso que Java, pero ese ejemplo me pareció malo.

Imagen de ezamudio

Sí, mal ejemplo

Es como los que quieren defender los productos orgánicos diciendo que saben mejor (bueno tal vez no sea así porque esto ya de plano es totalmente falso). Pero definitivamente, si quieres mostrar características del lenguaje, deben ser cosas que puedes hacer sólo en ese lenguaje. A veces es un poco difuso...

En Groovy por ejemplo, le agregan varios métodos a Object, List, etc, pero son métodos que no puedes usar desde Java (porque no están disponibles a la hora de compilar). Todo eso de each, eachLine, max, min, collect, find, findAll, etc, son características que tiene Groovy pero la implementación es que le agregan los métodos a las clases al momento de iniciar la JVM.

Pero si de plano esa clase que muestran de Scala se puede usar desde Java sólo importando un Jar, pues... mal ejemplo.

Imagen de greeneyed

Este señor es un escritor de

Este señor es un escritor de libros y conferenciante, así que su opinión como programador para mi tiene, en principio, escaso, escaso valor. Una vez que se acabó el chollo con Java, pasó a Flex; ahora que Flex ya no está en la cresta de la ola, toca cambiar y parece que el elegido es Scala. Y cuando Scala sea, si llega, un lenguaje estable, usado empresarialmente y ya no sea "la gran novedad", pues este señor cambiará de tema por que lo suyo no es programar, ni mantener programas escritos y eso hay que tenerlo en cuenta al valorar sus puntos de vista. Respetables como todos, pero hay que ver de donde vienen.

Me explico, si algo que a el le encanta es poco escalable o dificulta el mantenimiento a él no le afectará, por que una vez acabada la conferencia o escrito el libro, se va a otro sitio o a otro tema y listo. Pero si tu haces eso mismo y después te toca lidiar con los problemas que vengan después, quizás tengas otra visión diferente.

Una vez dicho esto, Scala tiene muchas cosas buenas que no tiene Java pero tiene otras que no lo son tanto. A lo mejor es por que mi trabajo no es repetir Hello World 20 veces, leer ficheros e imprimir lineas o medir microbenchmarks, pero la gran mayoría de comparaciones que la gente muestra no me valen más que para echar una carcajada (lo siento pero si alguien me dice que su gran problema con un lenguaje/programa es tener que escribir dos caracteres más en una linea no puedo evitar reirme).

En mi caso, me gusta más Groovy pero como ya he dicho Scala tiene sus cosas buenas.

Imagen de OscarRyz

Sobre los ejemplitos.

Si, lo mismo pienso, aunque luego reflexiono, ¿si el ejemplo fuera de unas ... 200, 300 LOC lo leería? mmmhh ( y no es taanto eh ) la verdad es que la mayoría de las veces mi respuesta es NO. A menos claro que fuera algo en lo que estoy trabajando y me ayudara a resolver el problema en turno.

Alguno de uds. que les gusta usan Groovy, no han tenido la oportunidad de usar Groovy++? Es groovy con una anotación más creo, con la diferencia que es de tipeo estático. Estaría padre ver una comparación en desempeño.

Imagen de greeneyed

De acuerdo

De acuerdo en que 200-300 LOC no se las leería nadie para ver como funciona un lenguaje, pero eso lo que indica es que sacar conclusiones de los ejemplillos que ponen en las noticias como esa es aventurado, por decirlo finamente. Yo para una comparativa algo más seria, prefiero implementar, por lo menos, al menos el mantenimiento o al menos la consulta de una tabla (http://www.jroller.com/greeneyed/entry/separating_concerns_business_logi...) ya que se parece más a lo que uso todos los días que a hacer las chorraditas con las que compara mucha gente.

Groovy++ no he tenido oportunidad todavía, pero le tengo ganas y parece prometer mucho. Si consiguen que el Eclipse, por decir uno, sea capaz de refactorizar el código Groovy++ como lo hace con Java, hay para plantarles un monumento :).

Imagen de OscarRyz

Refactoring sobre Groovy

Ahhh no pues ahí va a estar difícil y no por culpa de Eclipse sino por la naturaleza de los lenguajes dinámicos. Es mucho más difícil hacer refactoring no asistido ( sin que el IDE te tenga que preguntar: "Estas seguro?, estas seguro?" ) en un lenguaje de estos por la simple y sencilla razón que no se puede hacer un analisis estático de que cosa le pertenece a cada quien ( hence dynamic typing )

Imagen de ezamudio

codenarc

no se puede hacer un analisis estático de que cosa le pertenece a cada quien

seguro que no se puede?

Y el Groovy++ se ve interesante, habrá que probarlo...

Imagen de OscarRyz

Si seguro.

Si seguro.

Por ejemplo:

//Groovy
class Uno {
    def ejemplo() {
    }
}
class Otro {
    def ejemplo() {
    }
}

def usoA( o ) {
    o.ejemplo()
}

def usoB( o ) {
    o.ejemplo()
}

Si quisieras hacer un refactoring no asistido de algo tan simple como renombrar el método Uno.ejemplo() a Uno.ejemplo2() no habría forma se saber cual de las dos invocaciones cambiar, si usoA() o usoB() porque el analisis estático no te permitiría saber a cual le pertenece.

Se puede hacer si el IDE te pregunta ( o te deja elegir ) cual es el que quieres cambiar. Con Java, Scala o cualquier otro lenguaje con tipeo estático esto no es problema y no porque el IDE sea más o menos poderoso sino simplemente porque precisamente el tipeo estático te deja hacer este tipo de analisis, pues, estáticamente.

Imagen de greeneyed

El caso es que con Groovy++

El caso es que con Groovy++ se supone que puedes escojer utilizar tipado estático y ahí sí que el IDE podría entrar a trabajar con conocimiento. A mi me parece bien lo de poder "mezclar" tipado estático y dinámico por que la mayoría de gente en un 90%(NSDFC) de casos se usa dinámico por pereza de no declarar el tipo, no por que realmente haga falta que sea dinámico. Groovy++ parece hacer inferencia de tipos estilo Scala y supongo que por ese camino se podrían sacar cosas interesantes.
De todas formas, visto el nivel medio de los programadores, cualquier cosa que facilite que la gente haga chapuzas tiene su riesgo en cuanto entra más de un programador en juego.

Imagen de ezamudio

análisis estático

Oscar, originalmente dijiste que no se podía hacer análisis estático... CodeNarc hace análisis estático. Tal vez no para lo que quieres, ahora que ya lo definiste bien, OK en lo que dices tienes razón.

Imagen de OscarRyz

Desde el inicio dije .. bueno

Desde el inicio dije .. bueno hasta tu me citaste:

"...no se puede hacer un analisis estático de que cosa le pertenece a cada quien..."

Lo que si es cierto es que no había puesto el ejemplo, concreto e irrefutable como el que puse después B-)

Por cierto encontré un link ( lo puse también en el twitter ) de alguien que se siente igual que yo respecto a Scala y su hyperflexibilidad. Va por ahí:

Scala y la maldición de la fléxibilidad ( en inglés ).