Este artigo foi publicado originalmente no site do David e é republicado aqui com autorização
No passado mês de janeiro, o Exercism anunciou um novo programa chamado 12in23, no qual desafiou os participantes a experimentar 12 novas linguagens de programação em 2023. Cada mês tinha um tema (como "Abril Analítico" ou "Outubro Orientado a Objetos") e destacava linguagens específicas para experimentar. Adoro aprender coisas novas e tornei-me um bocado nerd de linguagens (de programação), por isso decidi tentar. 12 linguagens, 12 meses!
Agora que o ano está quase a terminar, estou incrivelmente satisfeito com a forma como o projeto correu. Experimentei com sucesso 12 linguagens novas, conheci pessoas fantásticas na comunidade do Exercism e, pelo caminho, fiz algumas contribuições fixes para projetos de código aberto! Neste artigo, faço um percurso por todas elas e falo do que retirei de cada uma.
Escolher as linguagens
Defini algumas orientações para o ano para aproveitar ao máximo a experiência:
- As linguagens deviam ser totalmente novas para mim ou, pelo menos, suficientemente desconhecidas para eu sentir que estava a aprender muito.
- As linguagens escolhidas deviam ser (potencialmente) práticas para eu continuar a aprender mais no futuro. Este projeto era só por diversão, mas quero passar o tempo a aprender coisas (pelo menos em parte) úteis.
- Instalava todas as ferramentas locais e o plugin do VSCode para qualquer linguagem que estivesse a usar. Queria comparar as linguagens em pé de igualdade, com o máximo de dicas de tipo e de intellisense possível. Na faculdade fiz todos os trabalhos de programação no Sublime Text, sem qualquer linter nem autocompletar. Preocupava-me que, se aprendesse a programar a usar todas essas ferramentas, ficasse demasiado dependente delas e não fosse um bom programador. Aconteceu precisamente o contrário. Quanta mais cognição consigo descarregar para as ferramentas, mais consigo pensar no problema em questão. Não memorizes coisas, memoriza como as encontrar.
Vamos a isso!

Janeiro (sem tema)
Quando janeiro começou, a equipa do Exercism ainda estava a escolher os temas mensais, por isso a linguagem desse mês ficou ao critério de cada um. Sem uma direção definida, comecei o ano com Go. Tinha feito um curso intensivo da linguagem em meados de 2022, mas não a usava muito desde então e não me sentia nada proficiente.
Go é uma linguagem interessante. O seu compilador rigoroso faz com que o Teu Programa Vai Estar Correto, e não avanças um centímetro enquanto ele não achar que é seguro fazê-lo.1 A sua abordagem verbosa ao tratamento de erros significa que nunca és apanhado de surpresa (à custa de escreveres if err != nil { return err } tantas, mas tantas, vezes). Faz um bom trabalho a tornar fáceis as coisas difíceis (como o paralelismo através de canais), mas também torna difíceis algumas coisas fáceis (a manipulação de strings). Tem uma biblioteca padrão robusta, o que significa que consegues fazer a maioria das tarefas sem módulos de terceiros. Gosto de como grande parte do ecossistema (formatação, instalação, compilação, etc.) é de primeira mão e está integrado no comando go. A linguagem tem os seus detractores, mas acho que cumpre em grande medida os seus objetivos de correção e facilidade de manutenção.
Não gostei assim tanto de a usar que vá pegá-la como primeira escolha, mas é uma ótima ferramenta para ter no cinto para programas sensíveis ao desempenho, como mostrar o caminho aninhado no prompt da minha shell.
Fevereiro Funcional

Fevereiro mergulhou de cabeça nas linguagens funcionais, que são um ramo matemático das linguagens de programação imperativas mais comuns. As linguagens funcionais são conhecidas pelas suas funções "puras" (sem efeitos secundários). Escolhi o Elixir, sobretudo porque o meu amigo Caleb já o usou no Advent of Code e fala maravilhas dele.
Gostei bastante do tempo que passei com o Elixir. Foi inspirado no Ruby (o que faz sentido; o seu criador, José Valim, foi um contribuidor central do Rails). Achei simples expressar conceitos funcionais como o encadeamento de métodos. Adorei todo o açúcar sintático que tornava isso fácil, como o operador de pipe (|>):
foo(bar(baz(new_function(other_function()))))
# becomes
other_function() |> new_function() |> baz() |> bar() |> foo()
Foi também a minha primeira vez a trabalhar com macros, ou código que escreve código. Como os programas em Elixir podem ser expressos numa AST que é ela própria código Elixir válido, é fácil escrever código que produz outro código válido. É um conceito mesmo fixe que o Elixir tornou fácil. Também gostei da forma como as funções podiam fazer correspondência de padrões com a forma dos seus argumentos, o que permitia encaminhar as chamadas de função para a implementação adequada:
defmodule TuplePrinter do
def print({a}) do
IO.puts("single")
IO.puts(a)
end
def print({a, b}) do
IO.puts("double")
IO.puts(a)
IO.puts(b)
end
end
TuplePrinter.print({1})
TuplePrinter.print({2, 2})
# single
# 1
# double
# 2
# 2
Parece o tipo de funcionalidade que ou é ótima ou transforma o teu código num autêntico espaguete. De qualquer forma, era um conceito fixe!
O Elixir também beneficia de correr dentro da máquina virtual BEAM do Erlang, o que lhe dá um grande ecossistema com que comunicar. É ótimo em concorrência e é o núcleo do adorado framework web Phoenix.
Embora não tenha uma necessidade imediata de usar Elixir, achei mesmo divertido de trabalhar e definitivamente algo que estaria aberto a revisitar. Além disso, foi um desafio interessante abordar problemas familiares de formas desconhecidas (nomeadamente, de forma recursiva).
Março Mecânico
Março focou-se nas linguagens de "sistema", que compilam para código de máquina.
De entre as opções, o Go era a única linguagem que me interessava.2 Ora, os leitores atentos vão reparar que eu já tinha feito um mês de Go, por isso repeti-lo não contaria para as minhas 12. Bem, quando o escolhi para janeiro, ainda não tinham anunciado os temas, por isso não percebi que me estava a encurralar.
Se soubesse que vinha aí o Bun, provavelmente teria experimentado o Zig, mas infelizmente não conseguia (ainda) prever o futuro. Assim, na ausência de uma escolha mais convincente, fiquei com um mês extra de Go, com a noção de que teria de repetir uma linguagem em algum momento mais tarde no ano.
Abril Analítico
Abril foi todo sobre linguagens populares na ciência de dados. Eu conhecia Python demasiado bem e fiz R numa aula de estatística na faculdade (e não gostei), por isso Julia, siga!
Gostei do tempo que passei com ela, mas sobretudo porque me pareceu tão semelhante ao Python. Foi um pouco desconcertante, como ser americano no Canadá. Tudo parece muito familiar, mas está só um pouco fora do sítio de uma forma difícil de identificar. De repente, alguém te oferece uma moeda de 2 dólares (ou uma função que é mesmo muito bem posicionada para fazer cálculo matricial) e percebes que já não estás no Kansas.
O que mais me saltou à vista foi o sistema de tipos do Julia. Era anotado (opcionalmente) como o sistema de tipos do Python, mas tinha verificações em tempo de execução para garantir que os argumentos correspondiam aos tipos declarados. Acho que o sistema do Python encontra o equilíbrio certo entre integrar-se nas ferramentas e não te atrapalhar, mas admito que os erros em tempo de execução do Julia para funções mal tipadas também foram úteis.
Em última análise, o Julia era porreiro, mas não é algo que espere vir a precisar no futuro.
Maio Transformador
Maio reforçou o "experimenta algo novo", destacando linguagens que fazem coisas muito invulgares. Aproveitei para experimentar o sempre popular Rust. Tenho de dizer, percebo o entusiasmo.
Embora o famoso borrow checker leve certamente o seu tempo a habituar, gostei da forma como me fez pensar nos meus programas com mais cuidado. O compilador era certamente rigoroso, mas as mensagens de erro iam muito além para me ajudar a corrigir problemas. Não vou dizer que fui especialmente produtivo na minha primeira semana, mas sinto que pelo menos consigo ver o topo da curva de aprendizagem.
O cargo, o gestor de pacotes do Rust, também merece uma menção especial. Embora não tenha instalado pacotes de terceiros, a sua funcionalidade de compilação, testes e formatação era excelente. O mesmo se aplica à sua extensão para o VSCode, que tinha todas as comodidades que esperaria de uma linguagem com tipagem estática como o Rust. Uma boa experiência de programador faz mesmo toda a diferença.
Embora sejam muito diferentes a nível de implementação, o Rust pareceu-me semelhante ao Go naquilo para que os usaria: fazer os programas correrem muito depressa. Muitas ferramentas em linguagens que uso regularmente estão a começar a virar-se para o Rust pelas suas características de desempenho, por isso prevejo vê-lo mais no futuro (mesmo que não seja eu a escrever Rust).
Verão dos Sexps (junho)
Junho foi o mês das S-expressions, uma forma sintática comum nas lisps. Escolhi o Clojure, uma linguagem funcional que corre na JVM.
Tinha escrito um pouco de Clojure há muitos anos. Tinha acabado de sair da escola e tornei-me o único responsável por um script diário crítico para o negócio no meu primeiro emprego. Escusado será dizer que foi um período complicado. Tinha curiosidade em ver se, agora que estava mais velho e mais sábio, seria mais acessível.
Fico contente por dizer que sim! A experiência funcional de fevereiro ajudou-me a pensar de forma recursiva e a sintaxe não era assim tão má quando se entrava nela. A sua interoperabilidade com a JVM também seria útil se eu a estivesse a usar num projeto maior.
Não me vejo a usar Clojure para nada quando há alternativas disponíveis, mas não foi uma experiência de todo desagradável.
Missão secundária: o Universal Test Runner!
Durante anos, usei uma pequena função bash para correr os testes unitários no meu diretório atual. À medida que trabalhava com todas estas linguagens novas, dei por mim a acrescentar-lhe linhas por conveniência; lembrar-me de correr t era muito mais fácil do que reaprender repetidamente o comando de teste específico de cada linguagem.
Como a lógica necessária ultrapassou o meu nível de conforto com bash, tirei algum tempo em junho e transformei o projeto numa coisa própria: o Universal Test Runner.
Partilhei-o no fórum do Exercism e a receção foi boa. Gostaram tanto que decidimos incorporar funcionalidades semelhantes no próprio CLI do Exercism (que está escrito em Go, um tema que, por sorte, eu tinha acabado de rever). Por isso, na segunda metade do ano, podia correr exercism test para correr a suite de testes da linguagem desse mês (um comando que é suportado nativamente no Universal Test Runner).
Se quiseres saber mais sobre o processo, escrevi sobre isso com muito mais detalhe quando foi lançado.
Enfim, continuando!
Julho Jurássico
Julho deu destaque a linguagens antigas. Este mês houve pouca escolha em termos de utilidade prática. Comecei pelo venerável COBOL, uma vez que ouvi dizer que ainda suporta muita infraestrutura crítica. Mas, com um casamento no início de agosto a aproximar-se, não tinha disponibilidade para me sentar e aprender uma linguagem tão diferente para mim. Por isso, mudei para o Visual Basic, como a opção menos má à vista.
Não há muito a dizer aqui. A linguagem parecia um pouco verbosa, mas suficientemente fácil de usar. Pelo que percebi, foi realmente concebida para o desenvolvimento de interfaces no Windows, por isso fazer pequenos exercícios torna difícil ter uma boa noção de tudo.
Agosto das Apps
Agosto foi inundado de linguagens para construir aplicações. Como era de esperar, houve muitas opções este mês. Escolhi o Swift. Enquanto pessoa que usa muitos produtos Apple, a linguagem feita à medida deles é bastante relevante para mim. Não era totalmente novo nela: publiquei uma única app para iOS em 2016, escrita puramente em Swift. Mas não tinha tocado na linguagem desde então e ela evoluiu muito, por isso achei que ainda contava.
Fiquei agradavelmente surpreendido com a facilidade de trabalhar com ela. Ao contrário de muitas das outras linguagens aqui, o Swift é bastante recente. Foi lançado em 2014 e beneficiou claramente das lições do design moderno de linguagens. Tem um gestor de pacotes de primeira mão, encadeamento opcional, funções de primeira classe e uma interpolação de strings sensata. Era ergonómico de ler e escrever, mesmo sem usar o Xcode.
Dito isto, o Swift é sobretudo útil no contexto de apps para plataformas Apple, que atualmente não escrevo. Embora tenha funcionado bem para os exercícios, não prevejo voltar a ele tão cedo. No entanto, adoro o facto de poder escrevê-lo no meu iPad!
Setembro Minimalista
Setembro explorou linguagens muito concisas ou pequenas. Escolhi o jq, uma ferramenta que uso e adoro há anos.
No entanto, sempre pensei nele apenas como uma ferramenta para trabalhar com JSON, e não como uma linguagem de programação de uso geral. Fiquei agradavelmente surpreendido ao ver que tem todos os atributos normais (funções, variáveis, ciclos, etc.), por isso pude escrever alguns programas bastante complexos:
# input: { "series": "1", "sliceLength": 1 }
. as {series: $series, sliceLength: $sliceLength} |
if
$series == "" then
"series cannot be empty" | halt_error
elif $sliceLength > ($series | length) then
"slice length cannot be greater than series length" | halt_error
elif $sliceLength == 0 then
"slice length cannot be zero" | halt_error
elif $sliceLength < 0 then
"slice length cannot be negative" | halt_error
else
.
end
| [range(0; $series | length)]
| map($series[. : . + $sliceLength])
| map(select(. | length == $sliceLength))
Foi divertido experimentar todas as funcionalidades do jq de que nunca precisei para transformações simples de dados. Embora as ferramentas aqui fossem um pouco escassas (sem integração com o editor, etc.), um conhecimento mais profundo da amplitude das funcionalidades do jq foi valioso.
edição: o DJ Adams no Mastodon chamou-me a atenção para o projeto jq-lsp e o seu plugin para VSCode correspondente. Desta vez deixei passar a oportunidade, mas vou dar-lhe uma vista de olhos no futuro.
Outubro Orientado a Objetos
Outubro mergulhou nas linguagens orientadas a objetos. Tenho um fraquinho por designs orientados a objetos, que espelham de perto a forma como visualizo os programas na minha cabeça. Escolhi o Ruby, que pode parecer uma escolha estranha.
Trabalho na Stripe, casa da maior base de código Ruby do mundo. Certamente não contaria como uma linguagem "desconhecida"? Embora tudo isso seja verdade, o nosso monólito Ruby parece muito distante do Ruby "padrão": tudo é verificado com o Sorbet, há muita geração de código e fazemos muita magia para que tudo funcione em conjunto e escale. Embora o Ruby dentro e fora da Stripe seja, em última análise, a mesma linguagem, trabalhar a escalas tão diferentes proporciona experiências muito distintas; queria saber como era a vida lá fora (nos anos desde que usei Ruby intensamente).
Em grande medida, foi bom! O próprio Ruby é ótimo e aponta a "felicidade do programador" como um dos seus principais objetivos, o que ressoou comigo. Gosto de como consigo muitas vezes adivinhar o nome de funções da biblioteca padrão que nunca usei. Gosto da facilidade com que se constrói código funcional e de como a sintaxe é ergonómica e expressiva.
Dito isto, fiquei surpreendido com o quão atrás do Python estavam as ferramentas de programação. Talvez esteja mal habituado, mas ter dicas de tipo no editor e ter linting e formatação extremamente rápidos é mais importante para mim do que pensava. Para uma linguagem tão popular como o Ruby foi no seu auge, fiquei surpreendido com o atraso que parecia ter nesse aspeto.3 Também nunca me habituei bem aos parênteses opcionais nas chamadas de funções, o que tornava menos direto passar funções como argumentos.
O Ruby continua a ser uma ótima linguagem e vou continuar a usá-lo no trabalho, mas não faz nada por mim que o Python não faça, pelo menos agora.
Novembro dos Nibbles
Novembro foi o mês mais difícil até agora: linguagens assembly. Embora já não seja comum escrevê-las à mão, é um tema útil e interessante de conhecer. Escolhi o WebAssembly pela sua importância para a web moderna e futura. Embora seja normalmente usado como alvo de compilação (e não algo que se escreva à mão), existem ferramentas para os malucos por aí.
Senti-me inesperadamente bem preparado para este mês. A sintaxe parecia-se com a do Clojure e a estrutura da linguagem parecia-se com a do TIS-100 da Zachtronics. Estranhamente, gostei de ter de começar do zero para cada operação; pareceu-me pitoresco. Odiaria se tivesse de fazer algo de facto desta forma, mas entretanto foi uma curiosidade divertida. Com comentários generosos, consegui escrever algo quase legível:
(module
(func (export "eggCount") (param $number i32) (result i32)
(local $res i32) ;; result
(local $remainder i32) ;; loop counter
(loop $loop
;; $res =
(local.set $res
;; $res +
(i32.add
(local.get $res)
;; $number % 2
(i32.rem_u
(local.get $number)
(i32.const 2)
)
)
)
;; $number //= 2
;; (keep on stack)
(local.tee $number
(i32.div_u
(local.get $number)
(i32.const 2)
)
)
;; this will keep looping until remainder is 0
br_if $loop
)
local.get $res
)
)
O maior obstáculo foi a falta de documentação e recursos. Era difícil até perceber que funções globais estavam disponíveis. Mas, dado que não vou de facto usar isto, uma vez que arranquei não me incomodou muito.
Dezembro fechou o ano com linguagens que não se encaixavam noutras categorias. Devido à repetição em Março, precisei de completar duas linguagens este mês.
Comecei pelo Wren. Criada pelo Bob Nystrom, famoso, entre outras coisas, pelo livro Crafting Interpreters. Fiquei encantado com a sua atenção ao detalhe, a sua pegada reduzida e o seu design top-down; tudo parece muito bem pensado. Esse nível de cuidado é evidente nos detalhes do âmbito das variáveis e das regras de privacidade. O seu compilador é pequeno e intensamente comentado, por isso é um ótimo recurso de aprendizagem se te interessas por implementações de linguagens.
O Wren é um pouco tosco e parece estar maioritariamente abandonado, mas acho que isso é aceitável para uma linguagem de brinquedo. Ninguém entra nisto à espera de estar pronta para produção. Há certamente espaço no mundo para linguagens que não são para produção.
Também: Lua
A minha segunda escolha este mês foi o Lua. Ao contrário do Wren, é incrivelmente prático. A sua fácil capacidade de incorporação faz com que apareça em muitos sítios, como no scripting do Redis e em mods do Factorio. O modelo de objetos levou um pouco a habituar, mas consigo ver como seria rapidamente produtivo. Ganhei rapidamente apreço pelas tabelas como uma estrutura que faz tudo. As ferramentas eram boas: o gestor de pacotes funcionava logo de início e a extensão para o VSCode suportava anotações de tipo em comentários sem complicações.
Embora não tenha nada para que precise imediatamente do Lua, é outra ótima ferramenta para ter na caixa devido ao seu uso generalizado.
Para terminar

Gostei desta digressão pelas linguagens mais do que esperava. Não só aprendi algumas competências práticas novas, como sinto que os meus horizontes se alargaram por completo.
Quanto ao que vem a seguir, acho que é aprender muito mais Rust. A sua importância no panorama das ferramentas de programação é evidente neste momento e quero garantir que consigo ler e contribuir para as coisas em que confio.
Não tenho um resultado concreto em mente, mas tenho o livro do Rust todo para ler, um curso de Rust para programadores de JS que meti nas despesas há um ano e uma track inteira do Exercism para completar. Gostaria de contribuir para pelo menos um projeto de código aberto (provavelmente o Just, um novo programa favorito meu), mas vamos ver onde o ano me leva.
Até lá, boas festas e bom resto de 2023!
-
Variáveis não usadas são um erro de compilação?? Quer dizer, vamos lá ↩
-
Na verdade, experimentei C++ primeiro (que não escrevia desde a faculdade). Simplesmente não era divertido, por isso abandonei-o ↩
-
Esta é outra forma de o Ruby "real" diferir da minha experiência dentro da Stripe, por isso fico contente por ter podido experimentá-lo dos dois lados ↩