Junio de 2017
Volumen 32, número 6
C#: hacer que C# sea más dinámico con Hyperlambda
Por Thomas Hansen
Tradicionalmente, solo había dos tipos de lenguajes de programación: los lenguajes compilados de forma estática y los lenguajes interpretados de forma dinámica. ¿Qué sucedería si existiese un tercer tipo de lenguaje de programación que encajara en cualquiera de estas categorías y tuviera el potencial para que los demás lenguajes pareciesen irremediablemente rígidos en comparación?
Hyperlambda es ese lenguaje, un entorno de ejecución Turing completo totalmente basado en Active Events (consulte mi artículo anterior en msdn.com/magazine/mt795187). Hyperlambda no es un lenguaje interpretado ni un lenguaje compilado. Ni tan solo tiene sintaxis. Hyperlambda es un lenguaje de no programación, quizás incluso un lenguaje antiprogramación. Técnicamente, ni tan solo es un lenguaje de programación. En esencia, Hyperlambda es simplemente un formato de archivo relacional que permite declarar estructuras de árbol. Se podría decir que tiene más en común con HTML y XML que con C# y JavaScript. No obstante, resulta que las estructuras de árbol solo pueden describir lo que solemos denominar árboles de ejecución.
Los árboles de ejecución son lo que la CPU ejecuta realmente. Todas las instrucciones de programación se pueden entender básicamente como ramas de un árbol, por las que la CPU se mueve al evaluar el código. Por ejemplo, un bloque if/else crea dos posibles ramas que son mutuamente exclusivas, y la CPU elige solo una en función de los resultados de la condición en la instrucción if. Fundamentalmente, lo que el equipo hace mientras ejecuta código es moverse por un árbol de ejecución y manipular su memoria durante el proceso. Esto implica que, si puede describir un árbol de ejecución y manipular la memoria, también puede describir cualquier elemento que haya descrito anteriormente mediante C# y JavaScript.
Todo es un árbol
Del mismo modo que todo es una "lista" en Lisp, todo es un "árbol" en Hyperlambda. A continuación, se muestra un ejemplo de seudocódigo de Hyperlambda que crea un árbol de ejecución tras analizarse:
if:condition
do-x:argument1
else
do-y:argument1
El resultado del análisis de este código es un objeto lambda. Para evaluar este objeto lambda, o árbol de ejecución, se puede invocar el evento activo eval en Phosphorus Five (P5). Puede pensar en un evento activo básicamente como un "objeto de función" que permite invocar un método creado, por ejemplo, en C#, con un objeto de gráfico o de árbol como único argumento. P5 implementa el patrón de diseño de Active Events.
Una vez creado dicho objeto lambda, el evento activo eval de P5 ejecuta de manera secuencial los nodos secundarios del nodo raíz y los invoca como eventos activos, de arriba abajo. El objeto lambda creado en el ejemplo anterior contiene cuatro nodos, dos de los cuales son nodos raíz. Por consiguiente, eval ejecutará la instrucción "if" antes que "else".
Por lo tanto, un objeto lambda se convierte en la "estructura DOM" creada por Hyperlambda. Si hubiese querido, podría haber usado XML en lugar de Hyperlambda para describir esta estructura de árbol. Pero sucede que Hyperlambda es el mejor método para describir estas estructuras de árbol. A menudo ayuda pensar en Hyperlambda como HTML o XML, y en los objetos lambda como la estructura DOM resultante.
La sintaxis de Hyperlambda es extremadamente simple. Todos los nodos pueden tener un nombre, un valor y nodos secundarios. A continuación, se enumeran todas sus estructuras de control principal:
- Un punto y coma separa los nombres y los valores de los nodos.
- Dos espacios abren la colección de elementos secundarios de los nodos.
De manera opcional, el valor de un nodo puede tener una declaración de tipos, insertada entre el nombre y su valor. La declaración de tipos es opcional y se usa con muy poca frecuencia. String es la declaración de tipos predeterminada de Hyperlambda.
Qué hace que Hyperlambda sea único
Un lenguaje estático, como C++ o C#, compila su código en algún elemento ejecutable por máquina de manera anticipada, antes de comenzar a ejecutar el resultado. Un lenguaje dinámico, como JavaScript, suele interpretar el código sobre la marcha, mientras lo ejecuta. Hyperlambda, en cambio, no sigue ninguno de estos procesos. En su lugar, se declara un árbol de ejecución, que se analiza en P5, lo que produce objetos lambda que se evalúan posteriormente mediante el evento activo eval de P5. Los objetos lambda que crea ni tan solo tienen en cuenta la sintaxis. Puede usar cualquier formato de archivo capaz de declarar estructuras de árbol relacionales con la finalidad de declarar sus objetos lambda, lo que significa que Hyperlambda acaba siendo un lenguaje de programación como lo son HTML o XML. No obstante, dado que sigue siendo un entorno de ejecución Turing completo, permite hacer todo lo que se puede hacer con cualquier otro lenguaje de programación. Quizás podría haber usado HTML para declarar mis objetos lambda, momento en el que HTML se habría convertido en un lenguaje de programación Turing completo.
Creación de ramas del árbol
Cada palabra clave de Hyperlambda es simplemente un evento activo. Al invocar estos eventos activos se suele invocar eval de forma recurrente según algún tipo de condición. Por consiguiente, Hyperlambda es sumamente extensible. La creación de una palabra clave equivale exactamente a la creación de cinco líneas de código. Aquí se muestra un ejemplo en C#:
[ActiveEvent (Name = "what-is-the-meaning-of-life?")]
private static void foo (ApplicationContext context, ActiveEventArgs e)
{
e.Args.Value = 42;
}
De hecho, ambas palabras clave if y else se crean como eventos activos de esta manera.
No es necesario usar C# para crear eventos activos o palabras clave. También puede crear sus propias palabras clave en Hyperlambda:
create-event:what-is-the-meaning-of-life?
return:int:42
En este punto, el lector observador podría darse cuenta de que, aunque Hyperlambda es sin duda una abstracción de altísimo nivel, en algún nivel filosófico también lo es de bajísimo nivel, podríamos decir que mucho más bajo que ningún otro lenguaje de programación, porque lo que modifica no es código, sino el propio árbol de ejecución. Esta característica de Hyperlambda presenta enormes beneficios, igual que el modelo DOM los presenta para HTML y XML. En primer lugar, permite código extremadamente flexible y automodificable. Esto significa que la separación entre lo que normalmente se considera crear código y ejecutar código es mucho más estrecha, lo que permite código que haga ambas cosas. La evaluación de un objeto lambda con algunos datos de entrada podría crear fácilmente una nueva lógica y ramas adicionales en el árbol de ejecución. Por ejemplo, si no le gusta un bloque if/else concreto por algún motivo, puede quitarlo de manera dinámica, incluso después de empezar a evaluar el objeto lambda que lo contiene. De hecho, el árbol de ejecución podría tener un aspecto completamente diferente según los datos de entrada que proporcione a los objetos lambda.
Del mismo modo que puede usar el modelo DOM para modificar partes de su página HTML en JavaScript, puede usar el "modelo de objetos" para modificar partes de sus objetos lambda durante la ejecución. Literalmente, su árbol de ejecución se convierte en una entidad dinámica que puede cambiar durante la ejecución.
La transformación una y otra vez entre el formato de archivo Hyperlambda, que se puede serializar y es persistente por naturaleza, y los objetos lambda, que son árboles de ejecución, es tan fácil como invocar un evento activo.
Búsqueda de su rama
Entre otros extraños rasgos de Hyperlambda, está el hecho de que no presenta variables. No me refiero a que no haya variables en el sentido de F#, donde todo es inmutable. Quiero decir literalmente que Hyperlambda no tiene variables. Seguro que está desconfiando en este momento. Después de todo, poder cambiar el estado del árbol de ejecución y la memoria es esencial para crear un entorno de ejecución Turing completo. No obstante, si puede cambiar el estado del árbol de ejecución, no necesita en realidad lo que solemos denominar variables.
En Hyperlambda, todo puede cambiar. Cambiar cualquier cosa en Hyperlambda implica simplemente hacer referencia a los nodos que quiere cambiar y proporcionar un origen para la operación de cambio. Así, lo primero que se necesita es una manera de hacer referencia a los nodos del árbol, lo que se consigue con expresiones lambda, como se describe a continuación:
_data:Thomas
if:x:/@_data?value
=:Thomas
say-hello:Yo boss
else
say-hello:Yo stranger
Este código muestra una expresión lambda, que hace referencia al valor del nodo _data y se proporciona como un argumento para la invocación del evento activo if. Esta invocación de if compara el resultado de la expresión lambda con el valor estático "Thomas" y, si el valor de "_data" es "Thomas", evaluará el objeto lambda dentro del nodo if. De lo contrario, evaluará el objeto lambda en el nodo else.
Una expresión lambda puede hacer referencia a los nodos que quiera del árbol. El resultado es un subárbol basado en el árbol original. La relación entre una expresión lambda y una estructura de árbol es, en cierto modo, análoga a la relación entre SQL y una tabla. Las expresiones lambda las pueden visualizar fácilmente quienes hayan creado expresiones XPath. Puede compararlas con LINQ o con "enumeradores precompilados", si lo desea. La última opción es en realidad cómo se implementan. Si cree que la compilación dinámica de consultas LINQ agrega valor, lógicamente debe creer que las expresiones lambda podrían poseer valor.
Poda del árbol
En este punto, todo lo que debe tener un entorno de ejecución Turing completo es la capacidad para cambiar partes del árbol. Aquí, lo hago con el evento activo "set":
_input:Thomas
_output
if:x:/@_input?value
=:Thomas
set:x:/@_output?value
src:Yo boss
else
set:x:/@_output?value
src:Yo stranger
El evento activo set funciona básicamente como el operador de asignación de C#. En este punto, tenemos un "lenguaje de no programación" Turing completo que le permite hacer todo lo que suele hacer con un lenguaje de programación tradicional, incluso sin haber creado realmente un lenguaje de programación o haber tenido en cuenta la sintaxis. En su lugar, se modifica el árbol de ejecución directamente mientras se evalúa el objeto lambda.
Existen más eventos activos que puede usar para modificar el árbol. Por ejemplo, "add" anexa un montón de nodos al resultado de una expresión lambda, lo que da lugar a uno o varios nodos adicionales, mientras que "insert-before" e "insert-after" funcionan de manera similar a add, excepto en que inyectan uno o varios nodos antes o después de un montón de nodos. Quitar nodos, valores o nombres es tan fácil como no suministrar un origen para set, momento en que simplemente se quitará el nodo, su valor o su nombre, según la declaración de tipos usada para la expresión.
El uso de construcciones como estas convierte C# en un lenguaje de programación superdinámico. Para ello, proporciona al programador las herramientas necesarias para poder cambiar el árbol de ejecución directamente. Se podría decir que estos rasgos de Hyperlambda lo convierten, de lejos, en el entorno de programación más dinámico del planeta. Incluso los lenguajes superdinámicos, como Lisp y JavaScript, parecen irremediablemente estáticos y rígidos en comparación con Hyperlambda.
En este momento, podría darse cuenta de que, en Hyperlambda, no existe absolutamente ninguna diferencia entre los datos y la lógica: la lógica y los datos son la misma cosa y no existe ninguna diferencia semántica entre ambos. Esto implica que puede cambiar tan fácilmente la lógica como los datos, lo que, a su vez, produce un modelo de ejecución superdinámico donde el árbol de ejecución puede cambiar completamente durante su ejecución. Esta singularidad se puede ilustrar con algunos casos de uso sumamente instructivos.
Alimentación del árbol
Caso de uso 1: Imagine que tiene 100 registros en su base de datos. Cada registro contiene algo de Hyperlambda. Si quiere, puede seleccionar todos estos registros, transformarlos en objetos y anexarlos a un objeto lambda de destino, para evaluar finalmente su resultado combinado. También puede crear un nuevo objeto de función fuera de estos registros, mantenerlos en un archivo en el disco y usar el archivo del mismo modo que invocaría una función.
Caso de uso 2: Si quiere, puede evaluar solo la mitad de una función y quitar las partes de la función que no desee ejecutar. Por lo que sé, ningún otro lenguaje de programación existente presenta esta capacidad. Se trata de una característica extremadamente útil.
Caso de uso 3: Si es necesario, puede extraer la mitad de los objetos lambda de cinco funciones diferentes, y crear una nueva función única derivada de las "mejores partes" de las funciones originales.
¿Cómo es esto posible? Un objeto lambda puede transformar cualquier otro objeto lambda igual que un archivo XSLT puede transformar un archivo XML. Si, por cualquier motivo, no quiere ejecutar ningún bucle while en el sistema, puede crear fácilmente un objeto lambda que transforme todos sus bucles while para convertirlos en bucles for-each y hacer que se ejecute en segundo plano como un proceso automatizado.
Por si no se dio cuenta, así es cómo funciona HTML en relación con el modelo DOM. En Hyperlambda, la modificación de objetos lambda es tan fácil como insertar, modificar o eliminar un elemento HTML en el modelo DOM con JavaScript. Si cree que esta funcionalidad aporta valor a HTML, lógicamente debe aceptar que podría agregar valor a la "lógica". Hyperlambda abre una dimensión completamente nueva en cuanto al desarrollo de software.
Caso de uso 4: Considere el CMS de System42 (bit.ly/2pwMOY9). Este CMS permite crear páginas lambda, que en lugar de mostrar simplemente HTML estático, son 100 % dinámicas e interactivas por naturaleza. "Vaya chollo" dirían algunos, y afirmarían que PHP puede hacer teóricamente lo mismo, como mínimo. No obstante, estas páginas lambda son también componentes reutilizables. La naturaleza dinámica de Hyperlambda significa que, por ejemplo, puede comprobar la existencia de un argumento "parent-widget" durante la ejecución de su página lambda y, en tal caso, en lugar de crear una página, puede inyectar la misma página como un control de usuario en otro widget en la suya.
De hecho, no es necesario modificar la página original; en su lugar, puede transformar el objeto lambda antes de evaluar la invocación de "create-widget". Categorizar las cosas como absolutos como se suele hacer en los lenguajes de programación tradicionales no tiene ningún sentido en Hyperlambda.
El resultado es que cada objeto lambda que se crea en Hyperlambda es también un componente potencialmente reutilizable que se puede insertar en otras partes del sistema. Esto implica que puede crear progresivamente sistemas cada vez más complejos, basados en sistemas que creó anteriormente. En un lenguaje de programación tradicional, debería elegir entre crear un sistema o crear un componente reutilizable. En Hyperlambda, estas opciones mutuamente exclusivas no tienen sentido, y todo tiende a formar parte de lo demás. Las características de capacidad de reutilización de Hyperlambda empequeñecen todo lo que vio anteriormente en su trayectoria de programación.
Caso de uso 5: En Hyperlambda, puede ejecutar repetidamente una carpeta del disco, de manera que se pasen argumentos a la ejecución y se elimine todo lo que solía limitar la programación tradicional. O bien, puede invocar un archivo exactamente como invocaría una función, de modo que la invocación del archivo devolviera varios valores al llamador. También puede invocar fácilmente el cuerpo de una solicitud HTTP POST transmitida al servidor, y reemplazar así de manera eficiente cada uno de los puntos de conexión del servicio web que haya creado con unas 5 o 15 líneas de código. Estas son cosas que hago casi cada día cuando uso Hyperlambda.
Caso de uso 6: En Hyperlambda, ni tan solo pensar en una página web como tal tiene sentido, ya que, solo con el reemplazo de un único ensamblado del grupo de aplicaciones, puede crear fácilmente una aplicación de Windows Forms usando exactamente el mismo código. En Hyperlambda, la reutilización del mismo código base para las aplicaciones web y las aplicaciones de Windows Forms es ridículamente fácil, incluso las partes de la GUI del código.
Cuando muestro Hyperlambda a otros desarrolladores de software, algunos tienden a descartarlo porque parece mucho más redundante que los lenguajes de programación tradicionales. Por ejemplo, el ejemplo de código anterior se podría haber descrito fácilmente con una sola línea de código en C#, mientras que fueron necesarias nueve líneas en Hyperlambda. Para las tareas simples, es cierto que Hyperlambda es en ocasiones más redundante. No obstante, Hyperlambda presenta un rasgo que atenúa este problema: la capacidad de transformar objetos lambda, lo que proporciona código mucho menos redundante a largo plazo. Básicamente, paga un precio bajo por anticipado (código más redundante a corto plazo) para terminar con código mucho menos redundante a la larga. Esto permite ofrecer mucha más funcionalidad con mucho menos esfuerzo. Hyperlambda permite un crecimiento de la productividad del software exponencial. Vamos a dejar que esta última frase se absorba un poco.
Hola mundo de Hyperlambda
La siguiente es la aplicación "Hola mundo" creada en Hyperlambda. Si pega este código en una página lambda, por ejemplo, en el CMS de System42, creará un botón en el que, al hacer clic, su valor interno cambiará a "I was clicked" (Se hizo clic). Descargue P5 e inicie la aplicación Aplicaciones/CMS para probarlo. A continuación, cree una página lambda y pegue este contenido en ella:
create-widget:foo-widget
element:button
class:btn btn-default
innerValue:Click me!
onclick
set-widget-property:foo-widget
innerValue:I was clicked
Se podría decir que siete líneas de Hyperlambda pueden reemplazar cientos de líneas de código en JavaScript, C# o HTML, según el marco, la biblioteca o el lenguaje que use para crear algo similar. Si lee todo el código detenidamente, es probable que adivine qué marcado HTML producirá. Hyperlambda tiende a acercarse más al lenguaje natural que otros lenguajes de programación. Lingüísticamente, se parece más al modo en que los humanos transmiten la información de manera natural a otros humanos que, por ejemplo, C# o JavaScript.
Como ventaja adicional, si crea su propio ensamblado de Windows Forms, con una implementación alternativa del evento activo create-widget mencionado anteriormente, puede usar exactamente el mismo código para crear una aplicación de Windows Forms.
¿Es Hyperlambda una bala de plata?
He sido acusado de anunciar balas de plata siempre que he abogado por Active Events. Admito que algunas de mis declaraciones pueden sonar a magia. Y sí, Hyperlambda crea código más redundante inicialmente, además de agregar sobrecarga a la ejecución de las instrucciones de programación, a causa de su semántica de implementación interna. En ocasiones, también encuentro errores y refactorizo mis cosas, lo que, con suerte, mejora el código. Evidentemente, Hyperlambda no es perfecto.
No obstante, el principal problema de Hyperlambda está realmente en su cabeza. Hyperlambda invalida completamente todo lo enseñado durante los últimos 50 años como procedimientos recomendados para el desarrollo de software. Y lo hace con estilo, siguiendo su propio ejemplo.
Sin embargo y a fin de cuentas, la respuesta sobre si Hyperlambda es una bala de plata no la tengo yo. Es algo que tendrá que averiguar por sí mismo. Es posible que le resulte útil consultar un ejemplo de un clon de GMail, Sephia Five, compilado completamente en Hyperlambda (github.com/polterguy/sephia-five). Sephia Five incluye criptografía PGP y protección antivirus y contra malware 100 % fiable, y funciona en todos los dispositivos capaces de mostrar HTML. Sephia Five es también varios órdenes de magnitud más eficiente en el uso del ancho de banda que GMail. Su versión inicial se compiló exactamente en cinco días, desde cero. Todas estas afirmaciones se pueden comprobar, así como reproducir y demostrar matemáticamente.
Para obtener más información sobre Hyperlambda, no dude en leer la guía que encontrará en github.com/polterguy/phosphorusfive-dox. Asimismo, puede descargar Hyperlambda junto con Phosphorus Five en github.com/polterguy/phosphorusfive.
Thomas Hansen crea software desde que tenía 8 años, cuando empezó a escribir código con un equipo Oric-1 en 1982. Ocasionalmente, crea código que hace más bien que mal. Entre sus pasiones se incluyen la arquitectura del software y las metodologías Web, AJAX y Agile.
Gracias al siguiente experto técnico de Microsoft por revisar este artículo: James McCaffrey