ClojureScript adota Async/Await
(clojurescript.org)- ClojureScript 1.12.145 teve o compilador alterado para gerar funções com a anotação
^:asynccomoasync functionem JavaScript - Agora é possível escrever funções em ClojureScript que esperam valores Promise com
await, melhorando a interoperabilidade com JavaScript - Também é possível usar
^:asyncem testes, validando comawaito resultado de chamadas de funções assíncronas - Na pesquisa recente sobre Clojure, o suporte a async functions representou a maior fatia entre as solicitações de melhorias do ClojureScript relacionadas à interoperabilidade com JavaScript
- Em casos comuns envolvendo APIs modernas de navegador e bibliotecas populares, diminui a necessidade de introduzir dependências adicionais, e a lista completa de mudanças pode ser consultada no item 1.12.145 do changelog do ClojureScript
Uso de ^:async e await
- O ClojureScript 1.12.145 teve o compilador alterado para gerar funções com a anotação
^:asynccomo JavaScript async function - Com o ClojureScript passando a ter como alvo o ECMAScript 2016, tornou-se possível escolher com mais cuidado as áreas de melhoria na interoperabilidade com JavaScript
- Agora é possível escrever funções em ClojureScript que esperam valores
Promiseusandoawait(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)))) - Também é possível usar
^:asyncem testes, validando comawaito resultado de chamadas de funções assí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 e lista de mudanças
- Na pesquisa recente sobre Clojure, o suporte a async functions representou a maior fatia entre as solicitações de melhorias do ClojureScript relacionadas à interoperabilidade com JavaScript
- Com essa melhoria, em casos comuns envolvendo APIs modernas de navegador e bibliotecas populares, diminui a necessidade de introduzir dependências adicionais
- A lista completa de correções, mudanças e melhorias pode ser consultada no item 1.12.145 do changelog do ClojureScript
- O ClojureScript 1.12.145 contou com contribuição do membro da comunidade Michiel Borkent
1 comentários
Comentários do Hacker News
Vi que o borkdude postou este tópico e também aparece listado como contribuidor desta release
Havia basicamente dois argumentos, repetidos há muito tempo, contra o suporte a async/await: que seriam necessárias mudanças profundas em todo o compilador de CLJS, e que macros de bibliotecas como Promesa já ofereciam uma conveniência parecida
Também havia quem dissesse que bastava usar core.async, ou que uma linguagem orientada a expressões não combina bem com async/await, mas isso parecia mais opinião individual do que o argumento principal repetido nos fóruns
No Slack dos Clojurians, o borkdude já tinha dito que não estava convencido de que adicionar suporte fosse inviável, e no fim parece que ele dedicou tempo e implementou mesmo, então sou muito grato
Um fato curioso é que o ClojureScript já suportava o paradigma assíncrono com a biblioteca core.async muito antes de o próprio JavaScript ganhar async/await
Não estou tentando diminuir o valor desta release; só acho incrível poder usar um novo recurso de linguagem que ainda não existe na linguagem hospedeira apenas adicionando uma biblioteca às dependências. Clojure é sensacional
Acho que descobri isso vendo uma palestra do David Nolen
Depois disso, fui migrando para usar o mínimo possível de JavaScript no frontend, e SSE é lindo justamente por ser unidirecional. Fico feliz de ver desenvolvedores de várias comunidades de linguagem se interessando por SSE hoje em dia
A palestra recente do David Nolen, “A ClojureScript Survival Kit”, também foi muito boa: https://youtu.be/BeE00vGC36E
Nunca dá para agradecer o bastante pelo trabalho que David “Swannodette” Nolen fez desde o começo com ClojureScript e core.async. O que mais surpreende nessa palestra é que ele realmente parece empolgado com a ideia de abandonar o ClojureScript em favor de Clojure puro no servidor, eventos enviados pelo servidor e só um pouquinho de JavaScript
A demo de fato começa por volta de 26:30. Ele mostra o uso de recursos de um webapp rodando no cliente e depois mostra o mesmo webapp rodando no servidor e sendo enviado ao cliente de forma unidirecional via SSE, com uso de recursos caindo quase a zero, o que é bem impactante
Não serve para todos os casos, mas usando uma biblioteca mínima de manipulação de DOM ficou muito mais fácil raciocinar sobre o webapp e seu estado. Antes eu precisava manter tanto um REPL de Clojure quanto um REPL de ClojureScript, além de lidar com muito tráfego bidirecional e estados difíceis de reproduzir; agora tudo está bem mais rápido e mais fácil de reproduzir
O output JavaScript fica maior, não há um modelo de erro embutido e, quando algo dá errado, ele é transformado em código de máquina de estados difícil de ler e depurar
Além disso, a macro
gonão consegue transformar código fora da própria S-expressão, o que incentiva funções a ficarem grandes demaisComo alguém da Cognitect disse, “core.async é uma bela bobagem”
É surpreendente ver Clojure/ClojureScript aparecendo com mais frequência nas redes ultimamente
Usei no trabalho por alguns anos por volta de 2012, mas como muita gente acabei saindo da JVM e indo para linguagens funcionais tipadas
Será que esse interesse renovado vem da programação com agentes? Será porque, sem verificação de tipos e com menos erros de sintaxe estranha ou palavras reservadas, fica mais rápido vasculhar código? Será que vem aí um renascimento das S-expressões?
As bases de código sérias em Clojure que conheço investem bastante em suítes de teste, então basta acrescentar algumas técnicas para ensinar a IA a usar a suíte de testes da forma mais eficaz e ela consegue render muito bem
Tenho colegas que fazem o agente interagir com o REPL, e dizem que isso é mais rápido por não pagar o custo de inicialização toda vez. Sou preguiçoso demais para ir tão longe, mas mesmo assim já é rápido o bastante
Clojure tem poucos atritos. Tudo é verdadeiro exceto
falseenil, não existe tabela de precedência de operadores, e a linguagem central dá suporte nativo a estruturas de dados imutáveis e persistentesTudo é expressão, e não uma mistura de operadores e expressões.
map,reduceefilterjá vêm embutidos e são usados naturalmente no código comumCódigo Clojure escrito há 10 anos ainda tem grande chance de funcionar hoje, e o ecossistema e os designers da linguagem tratam quebrar código quase como um tabu
Entre as linguagens que já usei, foi a mais livre para expressar ideias e a que menos me deu dor de cabeça. O Flowstorm, que é praticamente um depurador reverso, também é uma ferramenta dos sonhos para programar
É uma linguagem excelente se você quer viver satisfeito. Por outro lado, a maioria dos usuários toma isso como algo natural e por isso não fala muito sobre isso
Entre programadores que usam Clojure comercialmente, também há muitos que não entendem bem a linguagem e não são tão felizes. Muitas vezes não foi uma escolha deles, ou ainda não estavam prontos, e acho que antes de usar Clojure eles precisariam ter passado uns 10 anos sofrendo em outras linguagens com as coisas que detestavam nelas
Os vídeos de Rich Hickey sobre software são famosos e influentes, mas isso não significa que meus colegas os tenham visto ou sequer se importem com eles
Foi difícil lidar com uma base grande de Python sem tipos usando IA. Verificar se partes não cobertas por testes não quebraram é entediante demais
Quanto mais forte o sistema de tipos, melhor. Além disso, os modelos de IA são treinados em código, então quanto mais popular a linguagem, maior a chance de desempenho melhor. ClojureScript é legal, mas não é linguagem dominante, então imagino que a IA vá performar pior do que em JavaScript
No fim, se você está pensando em IA, é melhor escolher uma linguagem tipada ou, em uma linguagem dinâmica, pelo menos uma que tenha dicas de tipo
Isso é realmente grande. Desde o anúncio do Jank, não via tanta empolgação no ecossistema Clojure
Eu gostaria muito que alternativas ao JavaScript no frontend deixassem de ser obscuras e realmente se estabelecessem
Queria experimentar algo como ClojureScript, mas é difícil imaginar onde eu usaria isso além de projetos pessoais paralelos. Talvez seja mais fácil adotar em uma organização cujo backend já seja Clojure
Nunca usei em produção, mas já coloquei no ar alguns side projects e coisas para a família. Reagent, o wrapper de React para ClojureScript, sinceramente fez mais sentido para mim do que o próprio React
Você monta HTML com Hiccup, e componentes são apenas funções dentro de uma DSL de Hiccup, que na prática também é só uma lista, então o resultado fica muito elegante. O que é estático parece estático, o que é dinâmico parece claramente dinâmico, e tudo me pareceu ter bem menos mágica do que React comum
O que achei ruim foi tentar usar componentes não funcionais encontrados no NPM. Não é fatal, mas o código fica feio. Dava para consertar com wrappers, mas algumas bibliotecas JS ficam bem bagunçadas por padrão no cljs
A comunidade também é muito gentil e madura
Vale a pena começar convertendo scripts pessoais, pegar o jeito e sentir as vantagens. Não é melhor em todos os casos, mas, mais tarde, as pessoas podem vir pedir sua opinião, então você precisa estar bastante convencido
Ao introduzir uma tecnologia desconhecida, uma boa estratégia é escolher algo menos importante, reescrever e deixar lá. Se der problema, é fácil voltar atrás; se as pessoas começarem a gostar, você vai ampliando aos poucos
No passado, quando introduzi F# discretamente em uma organização .NET, comecei escrevendo em F# os testes menos importantes
https://blisswriter.app/
https://blog.nestful.app/p/how-we-dropped-vue-for-gleam-and
Faz tempo que não acompanho cljs de perto, mas lembro que originalmente ele era apresentado mais ou menos como “Clojure sobre JavaScript”. Pelo menos tenho a impressão de que o Rich explicava assim no começo
Entendi que a intenção era deixá-lo o mais próximo possível de mais um runtime
Mas esta mudança parece adicionar um recurso que só existe em cljs, e
awaitjá é uma keyword declojure.core, então isso também conflita com o próprio ClojureFico me perguntando se as duas implementações foram se separando com o tempo, ou se esse recurso era importante o bastante para os usuários aceitarem essa diferença
Isso é importante porque permite lidar com interoperabilidade com JavaScript sem incluir bibliotecas adicionais
Era um recurso que fazia falta há muito tempo, então esta release é muito bem-vinda
Parece melhor encapsular funções async/await em CSP. Clojure já tinha um padrão melhor
core.async não vai desaparecer, e se async/await se encaixar melhor do que uma implementação baseada em Promise, a parte
.cljsde core.async também pode ser atualizadaNão acho que essa nova dica de função vá fazer esse caminho desaparecer
https://clojurescript.org/guides/promise-interop#using-promi...
Não tenho muita certeza de como interpretar isso. Um dos pontos centrais de core.async não era justamente empurrar tudo isso para canais?
Não sei se ter uma keyword
asyncao estilo JavaScript é realmente um upgradeNão é obrigatório usar, e você ainda pode continuar usando core.async. Inclusive foi o recurso mais pedido na pesquisa recente do ClojureScript.