Jolt: una implementación de Clojure sobre Chez Scheme con arranque rápido y bajo consumo

Fuentes: Jolt: running Clojure on Chez Scheme, jolt-lang.github.io

Jolt: una nueva implementación de Clojure sobre Chez Scheme con arranque rápido y bajo consumo

Jolt, una nueva implementación del lenguaje Clojure que ejecuta sobre el compilador Chez Scheme, se presenta como una alternativa ligera al Clojure tradicional sobre JVM, con tiempos de arranque casi instantáneos y una huella de memoria reducida. El proyecto, anunciado por su autor en el blog Yogthos, busca ofrecer un reemplazo directo del Clojure sobre JVM adaptado a las prácticas modernas de desarrollo, especialmente en arquitecturas de microservicios y contenedores.

La motivación principal detrás de Jolt es superar las limitaciones de la JVM para casos de uso contemporáneos. Según el autor, la máquina virtual de Java fue diseñada en una era de servidores de aplicaciones monolíticos como Tomcat o WebSphere, donde los largos tiempos de arranque y el consumo intensivo de memoria resultaban aceptables. Sin embargo, ese modelo choca con el enfoque actual de desplegar flotas de contenedores aislados que arrancan de forma instantánea y escalan dinámicamente. Para abordar este problema, Jolt se apoya en Chez Scheme, un compilador JIT maduro que comparte las raíces Lisp de Clojure, lo que permite mapear la semántica del lenguaje de forma natural sin la fricción que supone forzarla sobre la JVM. Además, Chez ofrece un recolector de basura generacional optimizado para manejar la asignación y liberación rápidas de estructuras inmutables, características del flujo de trabajo típico en Clojure.

El proyecto no surge en el vacío. Existen otros dialectos de Clojure en desarrollo, entre los que destaca Jank, que avanza hacia una implementación completa pero se centra en la compatibilidad con el núcleo del lenguaje. El problema, según el creador de Jolt, es que la mayoría de las bibliotecas maduras de Clojure dependen de la interoperabilidad con la JVM, por lo que no funcionan en estos dialectos sin modificaciones. Jolt adopta una estrategia diferente: en lugar de reimplementar todo el ecosistema, proporciona adaptadores (shims) que replican los paquetes de la biblioteca estándar de Java más utilizados. El autor estima que la mayoría de las bibliotecas solo usan una superficie reducida de java.io, java.time, java.util y otros paquetes similares, por lo que mapear estos espacios de nombres permite ejecutar una porción significativa del stack existente. Este enfoque es similar al que sigue el dialecto let-go, que apunta a Go como plataforma.

En su estado actual, Jolt ya soporta un número destacado de bibliotecas populares. Es posible construir una aplicación Ring completa utilizando Ring, Reitit, Selmer y HoneySQL. La lista completa de bibliotecas cuyas suites de pruebas pasan íntegramente está disponible en el sitio de documentación oficial. Algunas bibliotecas, como Reitit, requieren descender hasta Java, pero Jolt permite crear shims personalizados. Un ejemplo es la biblioteca router, que implementa la clase Java reitit.Trie necesaria para el funcionamiento de Reitit. Cuando una funcionalidad no tiene un shim disponible, los desarrolladores pueden crearlos aprovechando bibliotecas maduras de Scheme o C y escribiendo código de pegamento que exponga esa funcionalidad como una API Java.

Jolt utiliza deps.edn para la gestión de dependencias y aliases, de forma similar a Clojure estándar, con la ventaja adicional de poder especificar dependencias nativas en C. El flujo de trabajo de desarrollo interactivo, piedra angular de Clojure, está plenamente soportado mediante nREPL, lo que permite iniciar una aplicación Jolt, conectarse desde el editor y desarrollar como si se tratara de Clojure sobre JVM. Además, nREPL puede integrarse en binarios compilados de release.

Otro aspecto destacado del proyecto es el esfuerzo por documentar formalmente qué constituye Clojure. El autor está construyendo una especificación de conformidad, una gramática EBNF y una colección de RFCs a medida que añade soporte para nuevas bibliotecas y descubre particularidades del lenguaje. Reconoce la invaluable contribución del equipo de Jank, cuyo clojure-test-suite proporcionó una base sólida para validar la semántica del núcleo. Sin embargo, esa suite no cubre el contrato con la JVM del que dependen muchas bibliotecas, por lo que gran parte del trabajo en Jolt se ha centrado en cerrar esa brecha. El corpus resultante compara cada valor esperado contra Clojure real sobre JVM y contiene alrededor de 3.500 casos, etiquetados como portables (:common) o dependientes del host (:jvm).

Bajo el capó, Jolt refleja nueve paquetes java.* de uso común en las bibliotecas de Clojure: java.io, java.lang, java.util, java.time, java.math, java.net, java.nio, java.sql y java.text, con aproximadamente mil implementaciones de métodos y campos. Es importante señalar que Jolt no reimplementa la biblioteca estándar completa de la JVM; algunas clases solo resuelven lo suficiente para que instance? y las verificaciones de tipo funcionen correctamente, y ciertos componentes como bean y proxy están documentados como parciales. Aun así, en muchos casos esto basta para que formas de interoperabilidad como Math/sqrt, (. StringBuilder) e instance? resuelvan contra comportamiento real. Sin una JVM debajo, la identidad de clase se sintetiza mediante un grafo de jerarquías que respalda instance? y (class x).

En definitiva, Jolt representa un esfuerzo significativo por acercar Clojure a los paradigmas de despliegue modernos, aprovechando la madurez de Chez Scheme y la compatibilidad con el ecosistema existente de bibliotecas. Aunque todavía queda camino por recorrer en cobertura y estabilidad, los resultados actuales sugieren que es viable ejecutar aplicaciones reales de Clojure fuera de la JVM sin sacrificar el acceso a las herramientas que han hecho del lenguaje una opción productiva para el desarrollo de software.