Scala: Parte 1
En este sitio se han discutido algunas de las cosas del lenguaje Scala, todas ellas muy interesantes y que han llamado la atención de los participantes en esta comunidad.
Tengo la intención de escribir varios artículos sobre este lenguaje de manera “disciplinada” lo que quiere decir comenzar desde el principio, aunque seguramente repetiré algunas de las cosas que ya se han dicho aquí. Eso no es traumático: a veces conviene leer lo que varios dicen sobre lo mismo.
Seguramente va a suceder que los posts queden “algo” extensos: pongo el parche antes que salga el grano, aceptando cualquier crítica al respecto y a otras cosas que pueda escribir aquí.
Comienzo entonces con una introducción al lenguaje. Para algunos será “pan comido” para otros será carbohidrato por digerir.
Scala es un lenguaje escalable
Scala es bautizado con ese nombre para precisamente decir que se inventa un lenguaje escalable.
El término escalable está “sobrecargado”. Es una palabra que hace alusión a diferentes cosas, dependiendo del contexto. En Arquitectura de software se utiliza para describir a uno de los atributos de calidad importantes de sistemas que manejan muchos recursos y para el cual deseamos que no se “degrade” con el crecimiento de esos recursos.
En el contexto de Scala, lo escalable se refiere mayormente a las posibilidades que ofrece el lenguaje de programar con él, sistemas simples y sistemas muy complejos con abstracciones ideadas por el programador, que producen programas con construcciones muy similares a las que el lenguaje soporta de manera nativa.
Muchas de las construcciones que son nativas en otros lenguajes, son en Scala clases en módulos de bibliotecas, pero con la posibilidad de programarlas con expresiones muy similares a las expresiones nativas del lenguaje, resultando entonces en programas más legibles con una notación de “alto nivel” y también con la posibilidad para el programador de extender esas abstracciones para satisfacer sus necesidades.
Martin Oderky, en su libro Programming in Scala usa la metáfora de la catedral y el bazar de Eric Raymond que este último utiliza en su artículo para comparar la construcción de software con código propietario y código abierto. Oderky expresa que Scala es más parecido a un bazar en el sentido que el lenguaje está diseñado para ser extendido manteniendo en los programas una notación de “alto nivel”.
Esa escalabilidad se logra gracias a varias cosas que se irán describiendo en estas notas, pero sin duda una de ellas es que Scala logra una “buena mezcla” de los conceptos de la programación orientada a objetos y la programación funcional en un lenguaje de tipado estático (ya sé que la palabra tipado no existe en español; tampoco Querétaro y fue seleccionada la palabra más bonita del español en el Día E).
Con la programación funcional, Scala permite construir expresiones potentes a partir de expresiones muy simples, mientras que la programación orientada a objetos brinda lo necesario para lograr un diseño arquitectónico sólido de grandes sistemas y poder entonces satisfacer requerimientos funcionales complejos y atributos de calidad obligados de esos sistemas.
Scala es un lenguaje orientado a objetos>
Todos los paradigmas de programación que han existido han tenido que buscar soluciones para estructurar el código. Cualquier programa, por simple que sea, tiene estructura y la forma más expedita de lograrla es agrupando datos y operaciones. Una vez que esto se logra hay que resolver otras muchas. El logro principal de la programación orientada a objetos es poder manipular esas estructuras (es decir los objetos) como valores dentro de un programa que pueden ser manipulados en funciones que los reciben como argumentos y que los devuelven como resultado, y que pueden ser almacenados en otros objetos. Algunos lenguajes OO llevan al extremo esa idea y consideran que todo lo que es manipulable en un programa son valores objeto. Smalltalk es el arquetipo de esos lenguajes.
Otros lenguajes OO consideran que por razones “prácticas” conviene un esquema más híbrido. Java es uno de esos lenguajes que separa su universo de valores en valores objeto y valores de tipo primitivo y que además considera necesario la inclusión de campos y métodos no asociados con esos objetos, introduciendo lo que conocemos como datos miembro estáticos y funciones miembro estáticas.
Los que inventan Scala regresan a la idea de Smalltalk y diseñan un lenguaje orientado a objetos puro, donde todo lo que se manipula en el lenguaje son objetos, y donde todos esos objetos son valores. Al hacer esto, establecen también que toda computación u operación que se realiza en un programa es la invocación a un método sobre un objeto, o dicho en otras palabras, toda computación está basada en el envío de mensajes entre los objetos que colaboran entre sí para resolver el problema en cuestión.
Alan Kay, el creador de Smalltalk, y según muchos el que acuña el término programación orientada a objetos, describe un programa con objetos como un sistema compuesto por muchas pequeñas computadoras (los objetos) que resuelven la tarea enviando entre ellos mensajes como un sistema distribuido de paso por mensajes, donde los mensajes se implementan con llamadas a funciones locales. Es una visión relevante para ver de forma natural la implementación de sistemas distribuidos reales con las técnicas y el método orientado a objetos.
Si todo es un objeto en Scala, y si todas las operaciones son invocaciones a métodos, puede entonces uno preguntarse por ejemplo cómo son tratados los operadores “comunes” que usamos en todos los lenguajes de programación. La respuesta es simple: NO existen operadores en el lenguaje, todos ellos son métodos. Así, la expresión
debe ser entendida como la invocación del método
parametrizada con el objeto
sobre el objeto
. No se trata de sobrecarga de operadores porque no existe en el lenguaje el operador
. Lo que realmente sucede es
Scala es un lenguaje funcional
Si hemos dicho que Scala es un lenguaje orientado a objetos puro, entonces cuando vemos el lado funcional del lenguaje, nos debe quedar claro que las funciones son objetos y que al ser objetos son valores: valores función y que pueden entonces manipularse como cualquier otro valor en el lenguaje. Esto se expresa diciendo que las funciones son valores de primera clase (first class values).
Podemos entonces anidar funciones, pasarlas como argumentos a otras funciones, devolverlas como resultado de otras funciones, utilizarlas como un medio poderoso para crear nuevas estructuras de control similares a las estructuras comunes como while, for, etc.
Si el lenguaje es funcional, entonces debe soportar el estilo funcional: toda computación en un lenguaje funcional debe basarse en la aplicación de funciones o dicho de otra forma: las operaciones de un programa funcional deben mapear los valores de entrada del programa en valores de salida sin producir efectos laterales y ser referencialmente transparentes.
La transparencia referencial se refiere entre otras cosas a la posibilidad de poder sustituir en un programa la llamada a un método para una entrada determinada, con su resultado, sin modificar la semántica o significado de ese programa.
Si Scala es un lenguaje OO y es también un lenguaje funcional, debe permitir entonces un estilo de programación OO y un estilo de programación funcional. Para esto, su sintaxis es “peligrosa” para los diabéticos pues hace un uso extensivo de azúcar sintáctica. A continuación viene un ejemplo con código en el REPL.
En el ejemplo creamos un objeto o valor función que denominamos
. El sistema de tipos en Scala incluye los tipos genéricos necesarios para crear objetos función. En este caso se está usando la clase Function1 (funciones de un argumento), parametrizada con los tipos Int para el argumento y su tipo de retorno. La expresión
es un literal función donde
es la lista de argumentos y
el cuerpo de la función. Noten que al definir
, el intérprete nos “da eco” de la firma de la función.
La línea
utiliza el estilo de programación funcional para aplicar la función: una expresión “dulce” para evitar escribir la línea
con el estilo orientado a objetos y que es lo que realmente sucede: invocar el método
sobre el objeto
.
Un vez que entendemos esto, pues lo natural es consumir esa azúcar. De hecho, todo objeto cuya clase disponga de un método
puede hacer uso de ese estilo funcional. Es lo que sucede cuando por ejemplo creamos una lista con
. En este caso el identificador
está haciendo referencia a un objeto así llamado que acompaña a la clase
y que dispone de un método apply (los objetos acompañantes de las clases).
Scala no reinventa la rueda
“Somos como enanos a los hombros de gigantes. Podemos ver más, y más lejos que ellos, no por alguna distinción física nuestra, sino porque somos levantados por su gran altura”
Bernardo de Chartres, circa 1159
Scala se basa en muchos desarrollos anteriores y al ser un lenguaje para la máquina virtual de Java es compatible con lo existente de ese lenguaje. Reutiliza los tipos de Java y además los amplía de manera implícita usando la técnica de conversiones implícitas. El código generado para los tipos valores hace uso de los tipos primitivos de Java para mantener en ejecución el desempeño esperado.
Los programas en Scala pueden ser usados en programa en Java con algunas restricciones al ser el primero un lenguaje más rico.
Scala es un lenguaje de tipado estático con un sistema de tipos que al comienzo causa terror por lo amplio del mismo. Evita lo verboso de los lenguajes tipados usando técnicas avanzadas de inferencia de tipos. Permite entonces al programador que desea ser muy explícito en sus programas, declarar el tipo de todo lo que declare o dejar que el compilador se encargue del asunto. La primera opción de especificar todos los tipos debe ser usada siempre que se diseñe un API que va a ser usado por terceros. Las anotaciones de los tipos sin duda que documentan un API.
Seguramente los que lean este post dirán que ese atributo no añade nada al “ecosistema” pues todos los lenguajes actuales son de alto nivel. Lo que Scala quiere destacar al decir que es de alto nivel es poder expresar las abstracciones de “alto nivel” con una sintaxis similar a la que usa con su soporte nativo. Son varias las cosas que hacen esto posible, entre ellas las de considerar que todos los “operadores” son métodos y un uso extensivo de notación infija para las expresiones. A continuación un ejemplo sencillo en Scala para calcular el factorial de un número entero grande ( el ejemplo es usado con frecuencia). El primer ejemplo utiliza la clase
y el segundo con la clase
Con
Con
En otros posts veremos que la mezcla OO y functional permite otras muchas cosas para ese “alto nivel” en el lenguaje. De especial importancia está la de poder crear nuevas estructuras de control para expresar cosas con una sintaxis idéntica a las estructuras de control nativas del lenguaje.
Para promover un lenguaje, casi todos los que lo inventan afirman que el lenguaje es simple. No comparto esa idea, como tampoco comparto la idea de que Java es un lenguaje simple. Si nos quedamos en la superficie de ellos, seguramente todos son simples, pero si nos sumergimos en sus entrañas, la simplicidad comienza a hacerse “menos simple”. Suena lógico que Scala sea menos simple que Java si es más rico que él.
Decir que es complejo no quiere decir que exija genios como usuarios. Los que conocen Java o cualquier otro lenguaje orientado a objetos tienen el background necesario para dominar ese lenguaje.
Pero este post ya es muy extenso y lo dejamos para la próxima.
- bferro's blog
- Inicie sesión o regístrese para enviar comentarios
Muy buena intro
Ya hasta le voy entendiendo más con los ejemplitos. La verdad no me he echado el clavado en Scala pero creo que esta serie de artículos terminará de convencerme de darle una probadita.
Muy bueno
Que bueno que te explayes, así no se pasa ningún detalle y para quien comienza desde cero (que creo que es la mayoría) está genial.
Te quedó excelente.
Excelente inicio
Me quede impresionado con este articulo, no solo por el tema en si, sino por la calidad de este.
Orale, no sabia que se podía hacer eso, crear nuevas estructuras de control, aunque ¿Para que o donde usarlas?
Esa es mi primer duda.
Saludos.
Está perfecta la
Está perfecta la introducción, yo me conseguí un libro de Scala, y con post como éste seguro le voy a entender a un ritmo más acelerado, gracias por su aporte a la comunidad Mr. bferro
DSL's
Lo de crear nuevas estructuras de control es muy útil para hacer DSL's (Domain-Specific Languages).
Re: Excelente inicio
Además de lo que menciona @ezamudio respecto de los DSL, también nos ayuda bastante con la concurrencia en Scala. Digamos que en Java pensamos en un hilo, o cuando pensamos en varios hilos manejamos todo a "más bajo nivel". Estas estructuras de control y otros yuyos propios de (o que te puedes aventar con) Scala nos permiten aplicar funciones o estructuras de control en paralelo y no de "uno en uno".
@bferro, muy muy buen intro, yo me estoy aventando el "Programming Scala: Tackle the multi-core complexity on the JVM" y pues hay dos tres cosas que entendía pero no sabía cómo explicarlas hasta leer este post. Espero y siga con esta serie de entradas.
Sobre la OO y Smalltalk >"El
Sobre la OO y Smalltalk
>"El logro principal de la programación orientada a objetos es poder manipular ...."
A mi me gusta más pensar en la POO como la representación del problema a resolver como si fueran objetos que tienen propiedades y maneras ( o métodos ) para manipular esos atributos. Sin embargo la forma en la que lo describes ayuda mucho a entenderlo sobre todo a quienes saben programación estructurada.
>"Alan Kay, el creador de Smalltalk, y según muchos el que acuña el término programación orientada a objetos..."
Smalltalk es un lenguaje de POO puro ( y si a Scala lo llamaramos puro también, entonces a Smalltalk lo deberíamos de llamar PURíSIMO jeje ) porque si bien, Java tiene una mezcla con la programación estructurada ( por ejemplo en "
") y Scala es híbrido ( Objeto-Funcional) en Smalltalk hasta las estructuras de control son mensajes a objetos.
Ejemplo [1]:
Regresando a Scala.
La naturaleza híbrida de Scala nace no del pragmatismo de hacer algo "usable" en primer lugar, sino del fracaso de su antecesor Funnel a su vez un intento por diseñar un lenguaje diferente a Java para poder programar sin las restricciones que Java impone [2]. Al darse cuenta que el paradigma reinante es OOP nace Scala como un punto intermedio entre Java y Funnel.
Es quizá por esta razón que el código escrito en Scala sea mejor cuando se usa como un lenguaje funcional mientras que el lado orientado a objetos sirve más como un frasco de miel para atraer a los programadres Java existentes. Es común oir que el código Scala es mejor cuando no lo escribe un programador Java y que básicamente las buenas prácticas de programación en Scala se reducen a no escribir OO.
Entonces lo que resulta un poco difícil al inicio es pasar la bardo inicial de Scala
Para ya después tomar una curva de aprendizaje normal.
Lo curioso es que los programadores de lenguajes de programación funcionales ( como Haskell o SML ) ven exactamente a Scala de la misma forma; como version "pobre" de ellos. Por ejemplo en la funcion factorial escrita con "pattern matching" en Scala, Haskell y SML respectivamente sería:
funcion factorial( n es Entero ) : regresa Entero
cuando n es 0 regresa 1
cuando n es otra cosa regresa n * factorial ( n - 1 )
Los tres son lenguajes de programación con tipeo estático, pero de los tres es Scala el que luce más ruidoso ( claro si es la primera vez que se miran los tres son inescrutables por supuesto ).
Conclusión:
Scala tiene ya casi 8 años y ha logrado lo que muchos lenguajes de programación funcionales no lograron que fue precisamente que se considere este paradigma como viable para la programación a gran escala ( ja ) es decir. Aún así la barda de entrada puede parecer un poco alta y es común cometer muchos horrores que vienen del legado de OO de Java y que la comunidad Scala amablemente nos irá diciendo como mejorar con un : "Lo estás haciendo mal!"[6]
Esperamos más ejemplos y explicaciones de bferro para cosas tan interesantes ( y desconocidas de la programación funcional ) como las conversiones implícitas, el currying, list comprenhension, monads y demás etcéteras que vienen en Scala.
Links:
[1]
[2]
[3]
[4]
[5]
[6]
No intento comparar lenguajes
En estas notas sobre Scala que espero seguir escribiendo no es mi intención comparar Scala con otros lenguajes funcionales o imperativos. Por supuesto que cosas de Java aparecerán con mucha frecuencia, porque persigo que las notas sean útiles para los que ya diseñan y programan en Java y también porque Scala ha tomado a JVM como su entorno de ejecución.
También pretendo "no saltarme el conocimiento" y primero aprender a caminar para después correr. De hecho estoy creando estas notas a partir del diseño de un curso sobre Scala que pronto promoveré (no va a estar caro).
Dr. En lo personal... estaré
Dr. En lo personal... estaré más que pendiente de ese curso ..... :D
Saludos!!!
Ándale mi @bferro ... habrá
Ándale mi @bferro ... habrá que subirle mucho de nivel ahora...
Yo también me pre-apunto ( a ver si hay becas ja jaaj )
Saludos.
Re: No intento comparar lenguajes
Estaría bien que hiciera algo de publicidad cuando tenga listo el curso, también me gustaría estar al tanto (saber cuando es, cómo sería, etc). Esperemos noticias.
Interesante
Es realmente interesante que vaya apareciendo información sobre Scala en español. Apenas hay nada.
Pero cuando dices:
Pero este post ya es muy extenso y lo dejamos para la próxima.
¿Dónde está la próxima? :)
@ezamudio
La capacidad de crear DSLs es precisamente una de las cosas que me gustaría evaluar en Scala. La rigidez de Java en este sentido es muy fuerte y hoy en día se están construyendo DSLs internos realmente sensacionales en otros lenguajes (sí, Ruby viene a la mente de forma inmediata :).
Juan - JuanMedin.com
ScalaTest
Pues apenas vi muy por encimita ScalaTest y me da la impresión de que lo que ofrecen es un DSL para hacer pruebas de código Scala, en Scala.