Mostrando entradas con la etiqueta raros. Mostrar todas las entradas
Mostrando entradas con la etiqueta raros. Mostrar todas las entradas

jueves, 3 de agosto de 2017

Cómo escribir tu propio intérprete (o compilador)

Interpreter Book

Suelo escuchar varios podcast mientras me muevo por Buenos Aires u otras ciudades en mi trabajo. Uno de los que sigo desde hace años es el de Scott Hanselman, que es quizá una de las personas que más me impactó dentro de lo que se conoce como la "comunidad Microsoft".

Scott, más allá de seguir trabajando para Microsoft en el grupo de ASP.NET y herramientas de Azure, es un tipo inquieto que mantiene varios podcasts e iniciativas, y sobre todo valoro su constante esfuerzo por lograr una industria más inclusiva, recibiendo a a gente de toda edad, raza, identidad u orientación sexual, religión o ideario.

Pero basta de elogios al amigo Scott. El tema que me atrajo especialmente en éste último podcast fue que entrevistaba a Thorsten Ball, quien auto-publicó el libro "Writing An Interpreter In Go", que trata básicamente de eso: recorre todos los pasos de escritura de un intérprete. En su caso del lenguaje Monkey que él diseñó para el libro mismo, y que es bastante similar a JavaScript o un montón de otros lenguajes de la familia de las llaves {}.

Más allá de que es un tema interesante, me gustó que la manera en que lo hace es utilizando lo más básico de Go, sin más que la librería standard, construyendo desde cero el parser y el lexer, y sin usar ninguna librería particular. Y por supuesto, utilizando TDD.

Es un libro que recorre en mayor detalle el camino constante del Maestro Ángel Java López, que como puede verse en su cuenta de GitHub escribe este tipo de intérpretes o compiladores todo el tiempo.

¿Por qué escribir un intérprete a esta altura? Básicamente porque las capacidades y el entendimiento de sus partes nos ayudan a ser mejores programadores en general, como llegado cierto punto un buen automovilista tiene que aprender de mecánica, o un rocker necesita aprender sobre ingeniería de sonido.

lunes, 23 de septiembre de 2013

¡Opa! ¿Y este framework?

Opa Up and Running

El framework Opa para JavaScript es más que un framework. En realidad, es un lenguaje + una librería, pero con un objetivo bastante ambicioso: Opa intenta cubrir con mismo lenguaje el desarrollo del lado cliente, servidor y el acceso a base de datos.

Según la introducción del proyecto en su repositorio de GitHub (traduzco):

Opa es un framework avanzado para JavaScript, compuesto de dos partes:

  • Un compilador para el lenguaje Opa, que presenta una sintaxis de estilo JavaScript pero con muchas mejoras;
  • Una librería JavaScript, que se usa en tiempo de ejecución.

Siguiendo la tradición de recorrer "Raros lenguajes nuevos", lo que más me interesó de Opa es el lenguaje mismo, y ese objetivo ambicioso, así que veamos algunas características:

Opa es open source (la librería con licencia MIT y el compilador GPL 3) y se autodefine como un lenguaje "full stack" ya que cubre todas las capas, y promete soportar aplicaciones seguras y escalables.

Las aplicaciones terminan ejecutándose sobre Node.js y usan MongoDB para el manejo de datos.

Soporta nativamente HTML5 y CSS y trata de automatizar la comunicación cliente/servidor con Ajax/Comet, y brinda un modelo de programación orientado a eventos y no-bloqueante (básicamente, respeta el modelo JS, pero subiendo el grado de abstracción).

Una de las promesas más atractivas de Opa es que se puede programar sin pensar (a priori) en la distinción entre cliente y servidor. El compilador analiza y distribuye el código, haciéndose cargo de toda la comunicación. Posteriormente, sin embargo, uno puede optimizar algunas situaciones utilizando los modificadores client y server.

Veamos el clásico "Hola, Mundo" en Opa:

Server.start(
   Server.http,
   { title: "Hola, Mundo"
   , page: function() {<h1>¡Hola, Mundo!</h1> }
   }
)

El programa se corre (habiendo instalado el compilador y las herramientas, obviamente) con el comando: opa hola.opa -- y la aplicación puede navegarse en http://localhost:8080

Algo interesante de Opa es que a pesar de compilar a JS (algo ya recurrente) es un lenguaje de tipos estrictos, aunque no hace falta declararlos porque se utiliza inferencia. Sin embargo, el compilador informa de cualquier tipo de violación y es bastante inteligente al sugerir incluso las opciones para solucionarlas.

Veamos un ejemplo más, con acceso a datos. Este ejemplo de los tutoriales cuenta clics y los almacena en una tabla:

import stdlib.themes.bootstrap

database int /counter = 0;

function action(_) {
    /counter++;
    #msg = <div>Thank you, user number {/counter}!</div>
}

function page() {
    <h1 id="msg">Hello</h1>
    <a class="btn" onclick={action}>Click me</a>
}

Server.start(
    Server.http,
    { ~page, title: "Database Demo" }
)

Como puede notarse en el ejemplo de arriba, el HTML queda completamente embebido como parte del lenguaje, sin necesidad de usar comillas para los literales, que además soportan interpolación sencilla. 

Obviamente, como Opa está basado en Node, también es posible usarlo en Linux, FreeBSD, OS X y Windows, y estando disponibles todos los fuentes, es posible compilarlo en otras plataformas también.

También tiene instrucciones para desplegar fácilmente aplicaciones en plataformas como Heroku, Cloud Foundry y otras, y existen packs para varios editores como SublimeText, Emacs, Vim, Eclipse, GEdit y otros.

Esto es una brevísima introducción porque realmente hay mucho por investigar en este interesante lenguaje. Si alguien profundiza, me encantaría que me cuente. Lo mismo haré por mi lado.

Y casi me olvido: como pueden ver en la ilustración más arriba, hay un libro publicado por O'Reilly.

viernes, 29 de junio de 2012

JetBrains + Nemerle = una dupla poderosa (+ video)

La gente de JetBrains, los cerebros a propulsión detrás de IntelliJ IDEA, ReSharper y toda una familia de IDEs especializadas, anunció recientemente la contratación del núcleo del equipo de desarrollo de Nemerle, uno de esos "raros lenguajes nuevos", completamente abierto, que revisé en este blog un año atrás.

Como explican en el anuncio, la incorporación se decidió en reconocimiento al increíble trabajo de Nemerle en la implementación del lenguaje y sus características de meta-programación, inferencia de tipos, etc. El foco del equipo estará por o tanto en el proyecto N2, un framework para desarrollo de lenguajes, un área a la que JetBrains se dedica muy especialmente y con evidente éxito.

Para que se den una idea sobre lo que genera esta gente, les dejo un video fresquito de una sesión sobre este lenguaje presentada por Igor Tkachev, del equipo de desarrollo, durante la reciente Norwegian Developers Conference en Oslo, a principios de junio (dura menos de media hora y está en inglés).

Da la impresión que el contacto y la posibilidad de fusión surgió a partir de esta época, así que puede ser un video para la historia (al menos para el equipo de Nemerle y JetBrains).

lunes, 26 de diciembre de 2011

Raros lenguajes nuevos: Dart (+ video)

Dart

Hace ya varios meses comenzó a circular el rumor de que Google estaba trabajando en un nuevo lenguaje. Entre los rumores se mencionaba un nombre: Dash, y un par de personas, conocidos para los que siguen las novedades en cuanto a lenguajes y máquinas virtuales: Gilad Bracha y Lars Bak.

En la conferencia GOTO, en Aarhus, Dinamarca, durante octubre de este año, se descorrió el velo y se presentó el nuevo lenguaje, con nombre definitivo similar al inicial: DART.

Efectivamente los autores detrás son Bracha y Bak. Bracha se ha autodenominado Teólogo Computacional Emérito, y conocido por ser coautor de la Especificación del Lenguaje Java y creador de los lenguajes StrongTalk (un entorno de Smalltalk, en realidad, creado antes de entrar en Sun) y más recientemente, Newspeak. Lars Bak es un reconocido en máquinas virtuales, habiendo liderado en Sun proyectos como HotSpot y Java ME, el entorno de ejecución de Self y más recientemente V8, el motor de ejecución de JavaScript abierto que forma parte de Google Chrome.

Google mantiene dos proyectos en paralelo respecto a la evolución de JavaScript: por un lado sigue apoyando fuertemente el desarrollo de EcmaScript (el verdadero nombre de JavaScript) para resolver algunos de los problemas de diseño que acarrea a lo largo de los años. Por otro lado, reconociendo que este es un camino que tomará muchísimos años y será complejo implementar algunas soluciones, mantiene también a Dart como una alternativa posible.

Dart es un lenguaje con muchas características conocidas, que no sorprende demasiado, pero con una base muy fuerte en su motor de ejecución, y mantiene la capacidad de ejecutarse nativamente dentro del navegador, algo que todavía no está completamente soportado ni en Chrome, pero si experimentalmente en una versión particular de Chromium (el proyecto abierto) siguiendo instrucciones particulares para compilarla.

Las características principales de Dart como lenguaje son:

  • Tipos estáticos opcionales (si no se declaran son dinámicos)
  • Herencia simple basada en clases con interfaces
  • Genéricos
  • Sintaxis muy similar a JS
  • Interpolación de strings
  • Lambdas
  • Modelo de aislamiento similar a Erlang (cada Isolate es un conceptualmente un proceso sin nada compartido, comunicándose por pase de mensajes, pudiendo correr en paralelo)

Las opciones de ejecución son realmente tres:

  • Compilar de Dart a JavaScript (la única opción que permite generar y ejecutar aplicaciones hoy en día)
  • Ejecutar el código Dart en su propia máquina virtual (aun no soportada realmente en ningún navegador, pero si en las herramientas Dart)
  • Crear una imagen (se trata de una imagen del heap de una aplicación que puede empaquetarse y reactivarse instantáneamente, similar a una imagen de Smalltalk).

Para utilizar Dart es necesario descargar y utilizar un conjunto de herramientas empaquetadas como un plugin de Eclipse, o para probar el lenguaje en un contexto más básico se puede utilizar Dartboard, un pequeño editor en linea con las herramientas detrás, en el servidor. En la imagen debajo pueden ver DartEditor corriendo en mi computadora:

Dart Editor

Para los más interesados, dejo un video y presentación de Gilad Bracha mismo en InfoQ (en inglés). Lamentablemente la gente de InfoQ no permite embeber el video de manera directa, pero es en parte porque ellos brindan una experiencia muy buena al sincronizar el video del presentador junto a las diapositivas en cuadros separados.

lunes, 8 de agosto de 2011

LangDay 2012: planeando una conferencia sobre lenguajes

imageEl grupo ErlAr, que reune a usuarios de Erlang en Argentina, está intentando organizar para el año próximo una conferencia sobre lenguajes de programación, con foco principal en los lenguajes “no principales”. Esto quiere decir concentrarse en aquellos que no son los más populares en la industria local, como C/C++, Java, C# o Visual Basic, sino en los lenguajes que tienen pequeñas pero pujantes comunidades de seguidores, como Python, Ruby, Erlang (claro) y otros menos conocidos, algunos experimentales, incluso.

Esta idea no puede ser menos atractiva para mi, que soy un apasionado del tema, y para quienes disfruten de la serie “raros lenguajes nuevos” que mantengo en este blog.

El proyecto, que por ahora se llama Lang Day 2012, tiene las siguientes características, según el sitio borrador:

Objetivo

Brindar un evento de uno o dos días que permita a los asistentes obtener una idea sobre lenguajes de programación emergentes la cual le permita comparar:

  • Paradigma dominante del lenguaje
  • Tipado
  • Características principales
  • Fortalezas/Debilidades
  • Filosofía
  • Estado actual/Planes futuros
  • Estado de documentación/comunidad
  • Casos de éxito
  • etc. (agregar otros de ser necesario)

Formato

El evento intentara organizar las charlas de manera que los asistentes puedan asistir a las charlas introductorias de todos los lenguajes y luego decidan en cuales quieren profundizar.

Por esto el track de introducción será en una sola sala donde las charlas introductorias se realizaran una tras otra con una duración de 45 minutos.

Luego el track avanzado se realizará en 2 salas por lo cual el asistente deberá decidir en cuales lenguajes desea profundizar.

Por ultimo se realizará antes de la charla de cierre una serie de lightning talks con duración de 15 minutos que permita presentar de una manera mas superficial lenguajes menos conocidos o no tan maduros

Lenguajes Principales

Estos lenguajes son los que se desea presentar en profundidad en charla introductoria y avanzada de encontrarse presentadores:

  • Python
  • Ruby
  • Erlang
  • Scala
  • F#
  • Go
  • Haskell

quizas:

  • Clojure

    Lenguajes Secundarios

    Estos lenguajes son los que pueden presentarse en una lightning talk:

    • efene
    • LayerD
    • coffescript + node.js
    • etc

    Calendario

    • Charla de apertura (de 30 a 60 minutos)
    • Charlas introductorias (sala única, 45 a 60 minutos)
    • Charlas avanzadas (salas múltiples, 45 a 60 minutos)
    • Lightning Talks (sala única) (entre 15 y 20 minutos cada una)
    • Charla de Cierre (entre 15 y 30 minutos)

    Charla de apertura

    La charla de apertura además de dar información sobre el evento debería informar sobre la utilidad de aprender nuevos lenguajes, y presentar una breve introducción a conceptos básicos que puedan ser utilizados durante las charlas como:

    • Tipado Estático, Dinámico, Progresivo, de pato, Fuerte vs Débil
    • Paradigma funcional, orientado a objetos y estructurado
    • Side effects, Single Assignment

      Para estar al tanto del avance del evento, pueden seguir la cuenta de Twitter @LangDayAr, y los interesados pueden completar esta encuesta sobre detalles que les gustaría como asistentes, o anotarse en este otro formulario si tienen interés en presentar sobre alguno de los temas.

      lunes, 25 de julio de 2011

      Google App Engine completó el soporte para Go

      La semana pasada el equipo de Google App Engine, la plataforma como servicio para ejecutar aplicaciones en la nube, anunció soporte para Go, uno de esos raros lenguajes nuevos, en este caso generado por el mismo Google, en lugar de surgir del ambiente académico o la comunidad de código abierto.

      Esto hace que Go, diseñado para ser un lenguaje de sistema de un nivel apenas superior a C++, eliminando los típicos problemas de manejo de memoria y aportando características específicas para situaciones de alta concurrencia y paralelismo.

      Go es un lenguaje “de llaves”, en la tradición familiar de C, pero sin necesidad de puntos y comas, al menos (las lleva pero el compilador se encarga de ponerlas solo). Veamos el clásico Hola, Mundo:

      package main

      import "fmt"

      func main() {
      fmt.Println("Hello, 世界")
      }

      Una de las características más interesantes de Go, y una de las que lo hace especialmente interesante para aplicaciones en la nube, es su implementación de co-rutinas, o funciones que pueden ejecutarse en paralelo, utilizando, casualmente, la sentencia “go”, pero además permite definir “canales” para mantener la comunicación entre procesos. Para los interesados que aún no lo hayan hecho, hay un buen tutorial de Go con muchos ejemplos.


      Quienes quieran probar Go en Google App Engine, pueden comenzar con las instrucciones en Google Code.

      jueves, 7 de julio de 2011

      Raros lenguajes nuevos: CoffeeKup (más y más cafeína)

      CoffeeKup

      El matemático Alfréd Rényi decía que "un matemático es una máquina que convierte café en teoremas", frase que usualmente se le atribuye a su compatriota y colega Paul Erdös, quien solía repetirla.

      Los programadores somos de alguna manera aparatos para convertir cafeína en algoritmos, lo que se hace explícito en la tradición de Java, JavaScript y el reciente CoffeeScript, todos inspirados en este alcaloide de venta libre.

      Siguiendo la tradición cafetera, Maurice Machado ha colaborado con un reciente experimento notable basado en Node.js y CoffeeScript. Como breve recordatorio, CoffeeScript es una sintaxis simplificada de JavaScript, con un estilo más sucinto, bastante similar a Ruby, que se está haciendo tan popular que ya viene integrado en la distribución de Ruby on Rails 3.1, por ejemplo.

      Lo que Maurice generó con CoffeeKup es un lenguaje específico de dominio (DSL) sobre CoffeeScript para generar el marcado completo de la página. Esto es, en lugar de escribir HTML, podemos escribir directamente toda la estructura de la página en CoffeeScript.

      Veamos el ejemplo clásico de http://coffeekup.org/:

      doctype 5
      html ->
        head ->
          meta charset: 'utf-8'
          title "#{@title or 'Untitled'} | My awesome website"
          meta(name: 'description', content: @desc) if @desc?
          link rel: 'stylesheet', href: '/stylesheets/app.css'
          style '''
            body {font-family: sans-serif}
            header, nav, section, footer {display: block}
          '''
          script src: '/javascripts/jquery.js'
          coffeescript ->
            $().ready ->
              alert 'Alerts are so annoying...'
        body ->
          header ->
            h1 @title or 'Untitled'
            nav ->
              ul ->
                (li -> a href: '/', -> 'Home') unless @path is '/'
                li -> a href: '/chunky', -> 'Bacon!'
                switch @user.role
                  when 'owner', 'admin'
                    li -> a href: '/admin', -> 'Secret Stuff'
                  when 'vip'
                    li -> a href: '/vip', -> 'Exclusive Stuff'
                  else
                    li -> a href: '/commoners', -> 'Just Stuff'
          section ->
            h2 "Let's count to #{@max}:"
            p i for i in [1..@max]
          footer ->
            p shoutify('bye')

      Como puede verse, se declara la estructura jerárquica de la página (cabecera y cuerpo), con sus atributos internos, y pueden anidarse los elementos como párrafos, divs, listas, y demás. Y claro, puede embeberse código en cualquier lado. No hay una diferencia directa entre la plantilla y el código.

      Parece una postura muy radical, pero me parece un espacio sumamente interesante a investigar. Los experimentos de Maurice estén disponibles en GitHub y no terminan en CoffeeKup. Hay otros relacionados, como Zappa y CoffeeScript-Bespin.

       

      jueves, 30 de junio de 2011

      Raros lenguajes nuevos: Cobra (video)

      Cobra - multiplataforma

      (gracias a José Romaniello por descubrirme este interesantísimo lenguaje)

      Cobra es un lenguaje multi-plataforma y multi-paradigma que combina una cantidad de características sumamente interesantes.

      Es obra de Charles Esterbrook, y su autor describe sus principios de diseño de la siguiente manera:

      1. Programación rápida y expresiva
      2. Rápida ejecución
      3. Tipado estático y dinámico
      4. Calidad soportada a nivel del lenguaje

      Por supuesto que suena ambicioso y vendedor, pero en principio, es bastante realista. Veamos cómo se soporta cada cosa:

      Programación rápida y expresiva

      Cobra tiene una sintaxis basada en Python (sobre todo) y Ruby, lo que lo hace mucho más legible que los lenguajes "con llaves y punto y coma". Entre otras cosas, en Cobra los bloques se determinan por indentación, las listas y diccionarios se pueden declarar como literales, hay comandos como print y assert de uso sencillo y poderoso, la manera de iterar y dividir listas es simple, y mucho más.

      Un ejemplo rápido de la sintaxis, con la definición de una clase:

      class Person
         """
         Declaración de una clase. Este comentario documenta la clase misma
         """
      
         var _name as String  # Declara variables de instancia (no estáticas)
         var _age as int
      
         cue init(name as String, age as int) # Inicializador (constructor)
            base.init
            _name = name
            _age = age
      
         def sayHello # Métodos
            # Los corchetes interpolan valores en las strings
            print 'Hello. My name is [_name] and I am [_age].'
      
         def divide(i as int, j as int) as int
            """ Este comentario documenta este método """
            assert j > 0 # Si el divisor 
            return i / j

       

      Rápida ejecución

      Esto es logrado a través del uso de tipos estáticos con inferencia permanente, sin perder las capacidades dinámicas para los casos necesarios.

      La implementación actual de Cobra utiliza la Infraestructura Comun de Lenguajes (CLI) de .NET/Mono, por lo que el compilador genera código intermedio (IL) que a su vez es es llevado a código nativo por el motor de ejecución de .NET/Mono como en otros lenguajes.

       

      Tipado estático y dinámico

      La mayor parte de la resolución es estática y en tiempo de compilación, mientras que siempre que haga falta puede utilizarse resolución dinámica en tiempo de ejecución, basada en Reflection de .NET y apoyándose en técnicas específicas de optimización.

      Veamos un ejemplo sencillo de una misma función declarada estáticamente:

      def add(a as decimal, b as decimal) as decimal
         return a + b
      

      ... o dinámicamente:

      def add(a, b) as dynamic
         return a + b
      

      En la práctica, no son la misma función, ya que la primera opera solamente con números decimales, y la segunda con cualquier tipo que soporte la operación suma.

      Obviamente la primer función es más rápida, ya que se verifica y compila, y no requiere más recursos que los operandos de un largo conocido (decimal), mientras que la segunda, al resolverse dinámicamente, es verificada en tiempo de ejecución y requieres más recursos para la conversión de parámetros, etc.

      Por otro lado, contar con ambas variantes es lo ideal, ya que podemos aprovechar el contrato estricto de los tipos estáticos para gran parte de la aplicación, pero con la flexibilidad de los dinámicos para las porciones que son más variables, o para facilitar el prototipado.

      Nótese que el soporte a tipos dinámicos de Cobra, comparado con el de C# o VB (a partir de .NET 4), es sintácticamente más sencillo, mucho más integrado a nivel del lenguaje.

      Calidad soportada a nivel del lenguaje

      Cobra soporta contratos de código (algo proveniente de Eiffel que .NET 4 soporta parcialmente), pruebas unitarias, comentarios para documentación y verificación de valores nulos en tiempo de compilación, todo como parte de su sintaxis.

      Veamos como las pruebas unitarias quedan embebidas directamente como parte de un método:

      class Utils
         shared
            def countChars(s as String, c as char) as int
               """
               Returns the number of instances of c in s.
               """
               test
                  assert Utils.countChars('', c'x') == 0
                  assert Utils.countChars('x', c'x') == 1
                  assert Utils.countChars('X', c'x') == 0  # case sensitive
                  assert Utils.countChars(' ! ! ', c'!') == 2
               body
                  count = 0
                  for ch in s
                     if c == ch
                        count += 1
                  return count

      Las aserciones, además, pueden usarse en cualquier parte del código, y arrojan una excepción con información útil para depuración si no se cumplen (no son un IF).

      Los contratos embebidos en el código permiten especificar pre y post-condiciones a los métodos, garantizando la consistencia antes de entrar y después de retornar el valor final. Por ejemplo:

      class Customer
      
         var _contacts as List<of Contact>
         get contacts from var
      
         def addContact(contact as Contact)
            require # Arroja excepción si algo no se cumple ANTES de entrar
               contact not in .contacts
               contact.name
               contact.customer is nil
            ensure # Arroja excepción si algo no se cumple DESPUES de salir
               contact.customer == this
               .contacts.count = old .contacts.count + 1
            body
               contact.customer = this
               _contacts.add(contact)

      Y otra característica muy buena de seguridad es que los parámetros o tipos que pueden recibir nil (llamado como en Smalltalk o LISP), son los que se declaran como tales, agregando al sufijo "?" al tipo, como en:

      def bar(s as String?)
         if s  # Es igual que preguntar "if s is not nil"
            print Utils.countChars(s, c'x')

       

      Cobra está escrito en Cobra

      Una característica más que quiero remarcar es que este lenguaje está escrito sobre si mismo. Por supuesto hay una parte del compilador escrita para la plataforma nativa (C# en este caso), pero el resto está escrito en Cobra mismo, lo que hace que el lenguaje tenga un nivel de depuración y prueba mayor que otros que se construyen generalmente sobre lenguajes de más bajo nivel. Esto está sucediendo en otros lenguajes a posteriori, como en el caso de PyPy o Rubinius, pero en Cobra fue un principio de diseño.

      Personalmente me parece uno de los lenguajes "experimentales" más interesantes y completos que he visto en los últimos tiempos, en parte porque se apoya en una plataforma que ya ofrece muchos servicios, y en parte por algunas de sus características maduras que y las herramientas con que ya cuenta (compilador, ejecutor de pruebas unitarias, generador de documentación, coloreador de sintaxis, etc).

      Y también cuenta con soporte parcial en algunas IDEs y editores:

      Visual Cobra es un complemento para Visual Studio que reconoce y colorea la sintaxis.

      Naja es una IDE completa escrita en Cobra que ademas del coloreo de sintaxis tiene soporte para lista de tareas basada en comentarios, soporte para proyectos y un diseñador de formularios que genera código Cobra.

      Y si uno prefiere un editor de texto hay muchos para los cuales hay complementos para soportar la sintaxis, incluyendo gedit, Notepad++, UltraEdit, Vim y TextMate (el que estoy usando yo), y mucho más para elegir según la plataforma que cada uno usa. Y para cualquier otro caso existe un detalle de las palabras clave y modificadores, de manera que en cualquier editor se puede partir del soporte para Python y cambiar estas listas.

       

      Finalmente, dejo este video de la presentación de Esterbrook en el Lang .NET Symposium 2008. Aunque la implementación del lenguaje maduró bastante desde entonces, muchos de los principios siguen igual.

       

      martes, 14 de junio de 2011

      Raros lenguajes nuevos: Nemerle

      Nemerle

      Uno de los principios de diseño del framework .NET, o más específicamente del CLI (Common Language Infrastructure) es, como su nombre lo indica, permitir implementar fácilmente una variedad importante de lenguajes.

      El CLI es una pieza estandarizada ante ECMA como un estándar abierto, y es lo que ha permitido la creación de implementaciones abiertas de .NET como Rotor y Mono.

      Pero también ha permitido la implementación de muchos lenguages (más allá de Microsoft) que comparten todo el ecosistema de herramientas y bibliotecas disponibles.

      Nemerle es uno de estos casos. Desarrollado en la Universidad de Wroclaw, Polonia, se trata de un lenguaje de tipos estáticos, casi un superset de C#, que soporta estilos de programación funcional y orientada a objetos, metaprogramación, lenguajes específicos de dominio y mucho más. Al estar basado en el CLI genéricamente, funciona en .NET y en Mono por igual.

      Siendo un superset, es posible compilar (con un par de toques en el archivo .csproj) fuentes C# en Nemerle.

      Dos de las características más distintivas de Nemerle son la inferencia de tipos y el uso de macros.

      Veamos algunos ejemplos de código, con inferencia de tipos:

      def d = Dictionary ();
      d.Add ("Code and Beyond", 42);
      foreach (s in args) {
        ...
      }

      Notese que no hace falta inicializar los tipos del diccionario, que son declarados y chequeados a partir del primer uso.

      En el caso de las macros, pueden escribirse cosas como:

      ExecuteReaderLoop ("SELECT nombre, apellido FROM personas WHERE nombre = $miNombre", dbcon,
      {
        System.Console.WriteLine ("Persona: {0} {1}", nombre, apellido) 
      });

      que enmascaran la creación del SqlCommand y el SqlReader, la clásica iteración y la obtención de las strings para los dos campos leídos, pero es importante ver que es mucho más que una función de una biblioteca, ya que en este caso se está interpretando la string conteniendo la sentencia SQL y generando el código chequeado correspondiente.

      Nemerle también tiene interpolación de strings más eficiente que en C#, ya que se ejecuta en tiempo de compilación, como en:

      $"Me llamo $Nombre y tengo $Edad años."

      donde las variables reemplazadas son chequeadas por el compilador, a diferencia de utilizar String.Format, donde se realizan en tiempo de ejecución.

      Es muy interesante además la sencillez para definir Macros, que no tienen nada que ver con las de C, y son descendientes directas de las macros de LISP. Veamos este caso que define un bucle hacia atrás:

      macro ReverseFor (i, begin, body) 
      syntax ("atras", "(", i, ";", begin, ")", body)
      {
        <[ for ($i = $begin; $i >= 0; $i--) $body ]>
      }

      que se usaría de esta manera:

      atras (i ; n) print (i);

      Más información sobre Nemerle en la wiki del lenguaje, y los más interesados pueden encontrar el repositorio en Google Code.

      miércoles, 1 de junio de 2011

      Raros lenguajes nuevos: ColdRuby

      ColdRuby

      En este caso no se trata realmente de un lenguaje nuevo, si no de una implementación interesante de Ruby.

      ColdRuby es un motor compuesto por tres partes:

      • Un intérprete de Ruby escrito en JavaScript
      • Un traductor de bytecode YARV (basado en Ruby 1.9)
      • Una máquina virtual basada en V8 (el motor de código abierto de Google) conectando las partes

      Sin embargo, estas tres partes pueden ser utilizadas en forma independiente o reemplazadas por otras. Así, ColdRuby puede compilar código Ruby a JavaScript para que lo ejecute un browser, o ser ejecutado directamente en Node.js (que utiliza V8 por debajo).

      Para los que todavía suponen que hacer algo así en JavaScript es una locura porque puede ser muy lento, los invito a mirar este emulador de completo de una PC escrito en JavaScript por Fabrice Bellard (autor de QEMU entre otras cosas), que bootea un Linux (funciona bien en versiones actualizadas de FireFox y Chrome, al menos).

      ColdRuby tiene unos cuantos detalles "raros" que surgen de las diferencias de diseño entre ambos lenguajes, como el modelo de herencia prototípica de JavaScript contra el usual, basado en clases, de Ruby. También hay detalles como la manera en que se mapean algunos tipos de datos, pero en todos esos sentidos se ha tratado de mantener la alternativa más pragmática para usos generales.

      La promesa es poder ejecutar Ruby dentro del browser (algo que hasta ahora era posible solamente con la combinación de IronRuby y Silverlight), e interactuar entre ambos lenguajes.

      El proyecto es temprano y todavia un tanto experimental, pero interesante.

      jueves, 20 de enero de 2011

      Raros Lenguajes Nuevos: CoffeeScript

      CoffeeScript

      CoffeeScript es un lenguaje que compila a JavaScript, y mantiene una premisa fundamental: sigue siendo JavaScript.

      El código es compilado a su equivalente, y es posible utilizar cualquier librería o extensión como en el ambiente original. El código final generado es prolijo y entendible, pasa las validaciones de JavaScript Lint y funciona en cualquier motor de JavaScript.

      Lo que CoffeeScript aporta es una sintaxis simplificada, inspirada en Ruby y Python, despojada de llaves y puntos y comas, bastante más legible pero con exactamente el mismo poder y características del JavaScript tradicional.

      Veamos algunos ejemplos:

      # Asignación:
      number   = 42
      opposite = true
      # Condiciones:
      number = -42 if opposite
      

      Esto genera el siguiente JavaScript:

      var number, opposite;
      number = 42;
      opposite = true;
      if (opposite) {
      number = -42;
      }
      

      Y aunque estos ejemplos suenan triviales, ya pueden notarse algunas abreviaturas importantes. Pero veamos un ejemplo más extremo, que utiliza declaración de funciones, espacios de nombre y comprensión de arrays:

      # Declaración de funciones
      square = (x) -> x * x
      
      # Declaración de un array:
      list = [1, 2, 3, 4, 5]
      
      # Funciones dentro de un espacio de nombres:
      math =
        root:   Math.sqrt
        square: square
        cube:   (x) -> x * square x

      # Comprensión de Arrays: cubes = (math.cube num for num in list)

      Y su equivalente en JavaScript:

      var cubes, list, math, num, square;
      var __slice = Array.prototype.slice;
      
      square = function(x) {
        return x * x;
      };
      
      list = [1, 2, 3, 4, 5];
      
      math = {
        root: Math.sqrt,
        square: square,
        cube: function(x) {
          return x * square(x);
        }
      };
      
      cubes = (function() {
        var _i, _len, _results;
        _results = [];
        for (_i = 0, _len = list.length; _i < _len; _i++) {
          num = list[_i];
          _results.push(math.cube(num));
        }
        return _results;
      })();
      

      ¿No es notoriamente más clara la versión en CoffeeScript?

      La sintaxis completa y referencia está disponible en línea.

      ¿Cómo funciona? El compilador está escrito en CoffeeScript (en la mejor tradición geek) utilizando Jison Parser Generator. La versión de línea de comando funciona sobre Node.js, aunque el compilador en si puede correr en cualquier motor de JavaScript.

      Algo muy interesante es que cualquiera que quiera jugar un poco no necesita instalar nada. Simplemente puede ir al sitio de CoffeeScript dentro de GitHub y elegir “Try CoffeeScript” en el menú superior para acceder a un editor en línea que permite escribir código CoffeeScript del lado izquierdo y va mostrando cómo se compila (en tiempo real, letra por letra) en JavaScript, como se ve en la figura:

       

      Try CoffeeScript

      viernes, 7 de enero de 2011

      Raros Lenguajes Nuevos: Scotch

      Scotch

      Siguiendo con la investigación sobre lenguajes experimentales o novedosos, hoy les presento Scotch, una creación de Ben Morris.

      Ben empezó este proyecto de lenguaje como un ejercicio en Haskell, pero se entusiasmó con el resultado y sigue adelante, después de haberlo dejado abierto en GitHub para contribuciones de cualquiera.

      Scotch es un lenguaje funcional que trata de mantener una sintaxis minimalista y expresiva, y agrega algunas características particulares a gusto de su creador:

      La asignación es siempre no estricta (lazy), de manera que si definimos "a = b", no estamos pasando valores, sino asignando una expresión. Si luego decimos que "b = 42", al inspeccionar el resultado de "a", se va a evaluar la secuencia y obtendremos 42.

      A diferencia de Haskell mismo, Scotch no es puro, y se pueden definir variables que mantengan estado, por lo que no queda libres de efectos colaterales como en lenguajes funcionales puros; también es débilmente tipado, lo que implica que podemos sumar números y strings, por ejemplo, y en lugar de dar error hace conversiones implícitas (siempre que pueda).

      Otra característica interesante es la resolución implícita en base a reconocimiento de patrones. Por ejemplo, para definir una función que calcule el factorial de un número, se hacen dos definiciones, una genérica y una específica:

      fact(n) = n * fact(n-1)
      fact(0) = 1

      La primera línea es la definición recursiva clásica, pero por si sola tiene el problema de que nunca terminaría, por lo que se puede definir el caso particular para cuando sea llamada con 0, de manera que en lugar de seguir llamándose a sí misma devuelva 1.

      Casi toda la librería de clases está basada en este mecanismo, utilizando recursividad de cabeza y cola (head/tail) y utilizando patrones para manejar los casos límites donde debe cortarse la recursión.

      Como casi todos los lenguajes funcionales, permite aplicación parcial y currying, como en este ejemplo:

      apply(f, x) = f(x)
      add(x, y) = x + y
      apply(add(10), 20)

      Aquí "apply" se define como la ejecución de una función que recibirá "x" como parámetro. La función "add" recibe dos parámetros y los suma, pero podemos aplicarla parcialmente como en el caso final, utilizando "apply".

      También tiene soporte para hilos de ejecución livianos (lightweight threads), o sea que no son hilos reales del sistema operativo, sino implementados por el lenguaje mismo (en este caso utiliza los que provee Haskell).

      Finalmente, el autor agregó Tipos de Datos Algebraicos (ADTs) que son como objetos livianos sin definición de clase, y funciones anónimas (lambdas).

      La gracia principal de ste intérprete es que la implementación es muy pequeña y es un buen ejercicio tanto de implementación de un lenguaje como de Haskell mismo.

      jueves, 30 de diciembre de 2010

      Raros Lenguajes Nuevos: Ela

      RSDN

      Sobre el final del año inicio una serie que espero continuar desarrollando durante el incipiente 2011: Raros Lenguajes Nuevos.

      La idea es dedicar cada tanto un post a algún nuevo lenguaje que aparezca en el radar, no necesariamente de los esotéricos, si no generalmente aquellos con posibilidades interesantes de ganar adopción o servir de campo experimental en ciertas áreas, aportando ideas que se incorporen en otros lenguajes más populares, como ocurre todo el tiempo en este campo.

       

      Ela

      En palabras de su creador, Vasily Voronkov: "Ela is a strict dynamically typed impure functional language" (un lenguaje funcional impuro, estricto y dinámicamente tipado). Y está implementado para correr sobre el CLR de .NET ó Mono. Analicemos estas características:

      Dinámico se refiere a que los tipos se definen y verifican en tiempo de ejecución, no de compilación, y estricto se refiere a que las asignaciones (por omisión) no se difieren, sino que ocurren en el momento. Los tipos son además fuertes, es decir que no hay conversiones implícitas (no se pueden sumar números y strings, por ejemplo).

      Exactamente al revés que en Haskell, que es funcional pero no-escricto (o lazy) por omisión, en Ela esta característica es opcional y debe ser explícita. Por ejemplo:

      let x =(&2+2)
      let y
      = x *2//La expresión '2 + 2' se evalúa recién en este momento

      El motivo de esto es que Ela está diseñado para ser funcionalmente impuro, también al contrario de Haskell. Esto significa que un programa puede tener efectos colaterales, o más simplemente, mantener estado (usar variables). Los lenguajes funcionales puros solamente admiten constantes y funciones, y no hay estado variable, lo que permite muchas cosas interesantes, pero implica un enorme cambio de mentalidad para cualquier programador que no proviene del mundo de las matemáticas.

      Finalmente, la sintaxis general de Ela es relativamente parecida a ML (o el reciente F#), utilizando secuencias, líneas de ejecución y comparación de patrones. Un ejemplo para asustarse (aunque en realidad no es difícil de entender después de algunas reglas básicas, sería:

      let filter f x::xs | f x  = x :: filter f xs;
                         
      |else= filter f xs;
                 _
      []           =[]

      Esto define una función filter que recibe un predicado, es decir una función que evalúa cada elemento en una lista para filtrarla. El uso de esta función para filtrar los elementos mayores que 5 es tan sencillo como:

      let filter' = filter (>5)

      Como siempre en programación funcional, se trata principalmente de describir el resultado a obtener más que detallar los pasos a seguir para obtenerlo, y Ela sigue bien esta tradición.

      ¿Qué diferencia a Ela de otros lenguajes?

      Además de características funcionales típicas como funciones anónimas (lambdas) y closures, y aplicación parcial.

      Sin embargo, Ela toma un decisión interesante respecto de cualquier otro lenguaje (que yo haya visto), y es que toda función debe recibir un único parámetro. No cero ni más de uno. Esto que parece bastante restrictivo se resuelve en forma general haciendo que una función reciba otra, generando encadenamiento, como en:

      let res = sum 23// por supuesto, devuelve 5

      pero no recibe dos parámetros, sino que sum recibe como entrada 2 y devuelve una función anónima que recibe como parámetro el 3. Veamos la definición de sum:

      let sum x y = x + y

      Esta es una técnica conocida como currying(que toma su nombre del matemático Haskell Curry, al igual que el lenguaje Haskell que toma la otra mitad). En programación funcional esta es una técnica muy usual para componer funciones, pero no es obligatoria.

      A primera vista parece raro, si, pero el hecho de pensar que toda función recibe un único parámetro cambia por completo la sintaxis del lenguaje, ya que no hacen falta más paréntesis ni separadores, y esto tiene un montón de consecuencias interesantes de analizar (y obviamente plantea varios desafíos).

      Otra interesante decisión de diseño es que todos los operadores son identificadores únicos, con lo que no hay posibilidad de utilizar un símbolo con diferente semántica en dos contextos. Por ejemplo, el operador "-" (signo menos) significa resta, por lo que el operador unario para indicar un número negativo es "--" (por ejemplo: --2). Raro otra vez, pero hay algunas razones válidas relativas a la capacidad de validación de expresiones en cualquier contexto.

      Es importante destacar que aunque el intérprete es totalmente funcional y puede ser embebido en código .NET o Mono, el proyecto está aún en nivel experimental.

      Para los interesados, la documentación más completa por ahora es la Wiki en Google Code (en inglés), o este artículo del autor (en ruso).