1 puntos por GN⁺ 3 시간 전 | 1 comentarios | Compartir por WhatsApp
  • ClojureScript 1.12.145 cambia el compilador para emitir las funciones con la anotación ^:async como async function de JavaScript
  • Ahora es posible escribir funciones de ClojureScript que esperan valores de Promise con await, mejorando la interoperabilidad con JavaScript
  • ^:async también puede usarse en pruebas, y await permite verificar los resultados de llamadas a funciones asíncronas
  • En la encuesta reciente de Clojure, el soporte para async functions representó la mayor proporción entre las mejoras solicitadas para ClojureScript relacionadas con interoperabilidad con JavaScript
  • En casos comunes que involucran APIs modernas del navegador y bibliotecas populares, se reduce la necesidad de introducir dependencias adicionales; la lista completa de cambios puede consultarse en la entrada 1.12.145 del changelog de ClojureScript

Uso de ^:async y await

  • ClojureScript 1.12.145 cambia el compilador para emitir las funciones con la anotación ^:async como JavaScript async function
  • Al pasar ClojureScript a apuntar a ECMAScript 2016, ahora es posible elegir con más cuidado las áreas de mejora para la interoperabilidad con JavaScript
  • Ahora se pueden escribir funciones de ClojureScript que esperan valores de Promise usando await
    (refer-global :only '[Promise])
    
    (defn ^:async foo [n]
      (let [x (await (Promise/resolve 10))
            y (let [y (await (Promise/resolve 20))]
                (inc y))
            ;; not async
            f (fn [] 20)]
        (+ n x y (f))))
    
  • ^:async también puede usarse en pruebas, y await permite verificar los resultados de llamadas a funciones asíncronas
    (deftest ^:async defn-test
      (try
        (let [v (await (foo 10))]
          (is (= 61 v)))
        (let [v (await (apply foo [10]))]
          (is (= 61 v)))
        (catch :default _ (is false))))
    

Contexto y lista de cambios

  • En la encuesta reciente de Clojure, el soporte para async functions representó la mayor proporción entre las mejoras solicitadas para ClojureScript relacionadas con interoperabilidad con JavaScript
  • Con esta mejora, en casos comunes que involucran APIs modernas del navegador y bibliotecas populares, se reduce la necesidad de introducir dependencias adicionales
  • La lista completa de correcciones, cambios y mejoras puede consultarse en la entrada 1.12.145 del changelog de ClojureScript
  • Michiel Borkent, miembro de la comunidad, contribuyó a ClojureScript 1.12.145

1 comentarios

 
GN⁺ 3 시간 전
Opiniones de Hacker News
  • Vi que borkdude publicó este hilo y que también aparece como colaborador de esta versión.
    Desde hace mucho tiempo, los argumentos en contra del soporte de async/await eran básicamente dos: que requería cambios profundos en todo el compilador de CLJS, y que macros de bibliotecas como Promesa ya ofrecían una comodidad parecida.
    También estaban quienes decían que bastaba con usar core.async, o que un lenguaje orientado a expresiones no encaja bien con async/await, pero eso se parecía más a opiniones personales que a los argumentos principales que se repetían en los foros.
    En Clojurians Slack, borkdude había dicho alguna vez que no estaba convencido de que agregar soporte fuera irrealista, y al final parece que sí le dedicó el tiempo para implementarlo, así que de verdad se agradece.

    • Primero Borkdude implementó async/await en Squint, su implementación alternativa de ClojureScript, para demostrar que era posible, y parece que luego llevó lo aprendido al compilador principal de CLJS.
  • Un dato curioso es que ClojureScript ya soportaba el paradigma asíncrono desde mucho antes de que JavaScript mismo tuviera async/await, gracias a la biblioteca core.async.
    No lo digo para restarle valor a esta versión; al contrario, me parece genial que puedas usar una función nueva del lenguaje anfitrión agregando solo una biblioteca como dependencia, incluso antes de que el propio anfitrión la tenga. Clojure es increíble.

    • Sí, totalmente. Lo usé mucho, funcionaba bien y, aunque tenía algunas rarezas, en la práctica llevábamos más de 10 años con algo equivalente a async/await.
      Creo que lo conocí por una charla de David Nolen.
      Después me fui moviendo a usar la menor cantidad posible de JavaScript en frontend, y SSE es hermoso precisamente porque es unidireccional. Me da gusto ver que últimamente desarrolladores de varios ecosistemas le están prestando atención a SSE.
      También estuvo buena la charla reciente de David Nolen, “A ClojureScript Survival Kit”: https://youtu.be/BeE00vGC36E
      Nunca se le va a poder agradecer lo suficiente a David “Swannodette” Nolen por todo lo que hizo desde los primeros días de ClojureScript y core.async. Lo que más me sorprendió de esta charla, en particular, es que de verdad se muestra entusiasmado con dejar ClojureScript y moverse hacia Clojure puro del lado del servidor, eventos enviados por el servidor y apenas un poco de JavaScript.
      La demo real empieza más o menos en el minuto 26:30. Primero muestra el uso de recursos de una web app corriendo en el cliente y luego enseña la misma web app ejecutándose en el servidor y empujándose de forma unidireccional al cliente por SSE; el uso de recursos cae casi a cero, así que el efecto es bastante fuerte.
      No aplica para todos los casos, pero al usar una biblioteca mínima de manipulación del DOM, se volvió más fácil razonar sobre la web app y su estado. Antes tenía que levantar tanto un REPL de Clojure como uno de ClojureScript, lidiar con tráfico bidireccional y con mucho estado difícil de reproducir; ahora todo es mucho más rápido y más fácil de reproducir.
    • Sí, pero en 2026 también hay muchas razones para evitar core.async.
      El resultado JavaScript se hace más grande, no tiene un modelo de errores integrado y, cuando algo falla, se transforma en código de máquina de estados difícil de leer y depurar.
      Además, el macro go no puede transformar código fuera de su propia S-expresión, así que empuja a que las funciones se vuelvan demasiado grandes.
      Como dijo alguien de Cognitect, “core.async es una tontería hermosa”.
  • Me sorprende que últimamente Clojure/ClojureScript aparezca más seguido en redes.
    Lo usé en el trabajo durante algunos años por ahí de 2012, pero como mucha otra gente terminé dejando la JVM y pasándome a lenguajes funcionales con tipos.
    ¿El interés de ahora será por la codificación con agentes? ¿Porque al no haber chequeo de tipos, ni tantos errores de sintaxis raros o palabras reservadas, es más rápido revisar el código? ¿Se viene el regreso de las S-expresiones?

    • En mi caso hice el camino inverso: de un lenguaje funcional con tipos a ClojureScript, y luego a Clojure hace unos 10 años.
      Los codebases serios de Clojure que conozco invierten bastante en suites de pruebas, así que si solo agregas buenas técnicas para enseñarle a la IA a usar la suite de pruebas de la forma más efectiva, puede avanzar bastante bien.
      Algunos colegas incluso hacen que el agente interactúe con el REPL, y dicen que es más rápido porque no paga el costo de arranque cada vez. Yo no he llegado a eso por flojera, pero incluso así ya va bastante rápido.
      Clojure tiene pocas fricciones. Todo es verdadero excepto false y nil, no hay tabla de precedencia de operadores y el lenguaje central soporta por defecto estructuras de datos inmutables y persistentes.
      Todo son expresiones, no una mezcla de operadores y expresiones. map, reduce y filter vienen integrados y se usan normalmente en el código común.
      El código Clojure que escribiste hace 10 años muy probablemente sigue funcionando hoy, y tanto el ecosistema como los diseñadores del lenguaje tratan romper código como si fuera un tabú.
      Es el lenguaje que más libertad me ha dado para expresar ideas y el que menos dolores de cabeza me ha causado. Flowstorm, que en la práctica es un depurador inverso, también es una herramienta soñada para programar.
      Si quieres vivir contento, es un lenguaje excelente. En cambio, la mayoría de sus usuarios lo da por hecho, así que no suelen hacer mucho ruido.
      Entre quienes usan Clojure comercialmente también hay mucha gente que no entiende bien el lenguaje y no la pasa tan bien. Muchas veces no fue una elección propia o todavía no estaban listos, y creo que antes de usar Clojure hay que haber vivido unos 10 años las cosas que odiabas de otros lenguajes.
      Los videos sobre software del creador de Clojure, Rich Hickey, son famosos e influyentes, pero eso no significa que tus colegas los hayan visto o que les importe.
    • Creo que el aumento reciente de interés se debe bastante a la publicación del documental de Clojure: https://clojure.org/about/documentary
    • Otra característica que encaja bien con la codificación con agentes es el desarrollo guiado por REPL. No entiendo por qué este enfoque no se extendió más en otros lenguajes donde, en teoría, también sería posible.
    • He hecho codificación con agentes en varios lenguajes, y los lenguajes con tipos encajan mucho mejor. El sistema de tipos corrige de facto muchos errores alucinados por el agente, sobre todo en refactorizaciones grandes.
      Trabajar con IA sobre un codebase grande de Python sin tipos fue duro. Verificar si no se rompió algo en las partes no cubiertas por pruebas se vuelve demasiado tedioso.
      Mientras más fuerte sea el sistema de tipos, mejor. Además, los modelos de IA se entrenan con código, así que cuanto más popular sea un lenguaje, más probable es que el rendimiento también sea mejor. ClojureScript está bien, pero no es un lenguaje dominante, así que esperaría peor desempeño de la IA que con JavaScript.
      En resumen, si vas a pensar en IA, es mejor elegir un lenguaje con tipos, o al menos uno dinámico que tenga ayudas de tipos.
    • Recuerdo que salió o se anunció un documental, así que puede ser por eso.
  • Esto sí está grande. No veía algo tan emocionante en el ecosistema de Clojure desde que anunciaron Jank.

  • Ojalá una alternativa a JavaScript en frontend dejara de ser algo tan de nicho y realmente se consolidara.
    Me gustaría probar algo como ClojureScript, pero me cuesta imaginar dónde usarlo fuera de proyectos personales. Tal vez sea más fácil adoptarlo en organizaciones cuyo backend ya está en Clojure.

    • Me pregunto si te preocupa que, por no ser un lenguaje dominante, tus colegas no lo conozcan, o si te preocupa que el lenguaje sea malo, quede abandonado o algo así.
      No lo he usado en producción, pero sí he desplegado algunos side projects y cosas para mi familia. Reagent, el wrapper de React para ClojureScript, honestamente me pareció más sensato que React mismo.
      Construyes HTML con Hiccup, y los componentes son solo funciones dentro del DSL de Hiccup; como ese DSL al final también es básicamente una lista, el resultado queda muy limpio. Lo estático se ve estático, lo dinámico se ve claramente dinámico y se siente mucho menos mágico que React normal.
      Donde sí me pareció feo fue al intentar usar componentes no funcionales encontrados en NPM. No es fatal, pero el código se pone feo. Se puede arreglar con wrappers, pero algunas bibliotecas JS en cljs vienen bastante desordenadas de fábrica.
    • No hay por qué tenerle miedo, es realmente bueno. Llevo 10 años usándolo para compilar apps complejas a código cliente altamente optimizado, y no lo llamaría algo oscuro.
      La comunidad además es muy amable y madura.
    • En vez de imaginarlo, empieza en pequeño. Si tu equipo tiene scripts de bash, puedes reescribir alguno con Babashka.
      Conviene empezar con scripts personales para agarrarle la onda y luego ir sintiendo sus ventajas. No siempre va a ser mejor, pero después la gente puede venir a pedirte consejo, así que tú mismo necesitas estar convencido.
      Cuando introduces una tecnología desconocida, una buena estrategia es escoger algo menos importante, reescribirlo y dejarlo ahí. Si sale mal, es fácil revertirlo; si a la gente le empieza a gustar, lo vas ampliando poco a poco.
      Cuando metí F# de contrabando en una organización .NET hace años, empecé escribiendo en F# las pruebas menos importantes.
    • Deberías probar Gleam. Lo uso en producción y estoy muy satisfecho.
      https://blisswriter.app/
      https://blog.nestful.app/p/how-we-dropped-vue-for-gleam-and
    • Después de leer https://hypermedia.systems/, llegué a la conclusión de que el mejor frontend es no tener frontend.
  • Hace mucho que no sigo cljs, pero recuerdo que originalmente se presentaba más o menos como “Clojure sobre JavaScript”. Al menos me parece que Rich lo explicaba así al principio.
    Yo entendía que la intención era acercarlo lo más posible a ser solo otro runtime.
    Pero este cambio parece agregar una función que existe solo en cljs, y await además ya es una palabra clave de clojure.core, así que también choca con Clojure mismo.
    Me pregunto si las dos implementaciones se fueron separando con el tiempo, o si esta función era lo bastante importante para los usuarios como para justificar esa diferencia.

  • Esto es importante porque permite manejar la interoperabilidad con JavaScript sin meter bibliotecas adicionales.
    Era una función que hacía falta desde hace tiempo, así que esta versión se siente muy bienvenida.

  • Me parece que una mejor forma de tratar funciones async/await sería envolverlas con CSP. Clojure ya tenía patrones mejores.

    • Esta versión trata de exponer en ClojureScript una característica nativa del lenguaje anfitrión.
      core.async no va a desaparecer, y si async/await encaja mejor que una implementación basada en Promise, incluso la parte .cljs de core.async podría actualizarse.
    • Eso todavía se puede hacer. En el mundo de ClojureScript ya era posible desde hace varios años; al final, todo eso no deja de ser Promise.
      No creo que este nuevo hint de función vaya a hacer que ese enfoque desaparezca.
      https://clojurescript.org/guides/promise-interop#using-promi...
  • No estoy muy seguro de cómo tomar esto. Siento que uno de los puntos principales de core.async era justamente empujar todo este tipo de cosas hacia canales.
    No me convence del todo que tener una palabra clave async al estilo JavaScript sea realmente una mejora.

    • Esto es para usar funciones de JS sin traer dependencias adicionales como core.async.
      No es obligatorio usarlo y todavía puedes seguir usando core.async. De hecho, fue la función más pedida en la encuesta reciente de ClojureScript.