1 pontos por GN⁺ 2026-04-25 | 1 comentários | Compartilhar no WhatsApp
  • Compilador AOT que realiza inferência de tipos do programa inteiro no código-fonte Ruby, converte para código C e gera binários nativos autônomos
  • Desenvolvido diretamente por matz, criador do Ruby; o próprio backend do compilador é escrito em Ruby, em uma estrutura self-hosting que compila a si mesmo
  • Cerca de 11,6x mais rápido que o miniruby (Ruby 4.1.0dev); Conway's Game of Life teve ganho de 86,7x, ackermann 74,8x e mandelbrot 58,1x
  • O pipeline de compilação usa um parser baseado em Prism para converter Ruby em texto de AST, depois o backend self-hosting faz a inferência de tipos e a geração de código C, e um compilador C padrão cria um binário standalone
  • Suporte a uma ampla gama de recursos do Ruby, incluindo classes, herança, blocos, tratamento de exceções, Fiber, engine de Regexp NFA embutida, Bigint com promoção automática e pattern matching
  • Classes pequenas com até 8 campos escalares são alocadas automaticamente na stack como value types, eliminando completamente o overhead de GC (1 milhão de alocações: 85ms → 2ms)
  • Encadeamento de strings a + b + c + d é achatado em um único malloc, e split dentro de loops reutiliza sp_StrArray para eliminar alocações desnecessárias
  • Diversas otimizações em tempo de compilação, como hoisting de comprimento invariante de loop, propagação de constantes, inline automático para métodos com até 3 instruções e encerramento antecipado da inferência iterativa (~14% de redução no tempo de bootstrap)
  • Os binários gerados têm zero dependências de runtime e podem ser executados apenas com libc + libm
  • eval, metaprogramação, Thread e Mutex não são suportados (apenas Fiber é suportado)
  • Licença MIT

1 comentários

 
GN⁺ 2026-04-25
Opiniões no Hacker News
  • Se foi o Matz que fez, então ele certamente conhece bem os limites da semântica do Ruby, o que passa confiança
    Minha dissertação de mestrado também foi sobre um compilador AOT de JS; ele até funcionava, mas as restrições sobre os dados de entrada eram grandes demais, então acabei abandonando
    Na época, os desenvolvedores de JS não estavam acostumados a seguir esse tipo de restrição por conta própria, e entradas inerentemente desconhecidas, como JSON.parse, eram um grande obstáculo
    Hoje, com TypeScript, isso pode ser bem mais viável do que naquela época
    Mesmo olhando apenas para o cálculo lambda em geral, os limites da inferência de tipos são claros, e artigos do Matt Might ou trabalhos como Shed-skin para Python mostram restrições parecidas
    Fico curioso para saber o quão comuns são eval, send, method_missing e define_method em código Ruby real, e também como normalmente lidam com parsing sem tipos, por exemplo entradas JSON

    • Esse design parece bem pragmático
      Fazer o parsing de Ruby é tão difícil que chega a ser mais complicado do que a própria tradução, então eles usam o Prism, e o resultado gerado é C
      A semântica básica do Ruby em si não é tão difícil de implementar assim
      Em contrapartida, eu estou preso a um antigo compilador AOT self-hosted feito em Ruby puro, e escolhi de propósito um caminho muito mais difícil ao insistir em usar um parser próprio
      Aprendi cedo que os primeiros 80% podem ser montados mais ou menos e ainda assim uma boa parte do código Ruby já roda; o verdadeiro "segundo 80%" difícil está concentrado nas coisas que o Matz deixou de fora neste projeto e no mruby, como codificação e todo tipo de recurso periférico
      Sinceramente, o Ruby tem várias funcionalidades que eu nunca vi em código real, então não acharia estranho se algumas fossem descontinuadas
      send, method_missing e define_method são muito comuns
      As restrições são parecidas com as do mruby, e ainda existe espaço de uso mesmo dentro delas
      Suporte a send, method_missing e define_method é relativamente fácil
      Já suporte a eval() é extremamente doloroso
      Ainda assim, uma grande parte do uso de eval() em Ruby pode ser reduzida estaticamente à versão com bloco de instance_eval, e nesses casos a compilação AOT fica bem mais simples
      Por exemplo, se a string passada para eval() puder ser conhecida estaticamente ou decomposta, há bastante margem para resolver
      Na prática, muitos usos de eval() são desnecessários ou apenas uma forma simples de contornar limitações de introspecção, então dá para tratar com análise estática
      No meu compilador, se isso virar gargalo, pretendo atacar essa parte primeiro
    • É preciso haver bastante desse tipo de recurso para criar a mágica ao estilo Rails
      Ingestão de JSON sem tipos provavelmente também tende a usar esses mecanismos
      Se você remover isso, sobra uma linguagem pequena e fácil de ler, não tão fortemente tipada quanto Crystal, mas também sem depender de metaprogramação tanto quanto o Ruby oficial
      Então o potencial parece bem grande, mas no fim só o tempo vai dizer
    • Se a abordagem fosse compilar Ruby para Objective-C, talvez desse para suportar todos os recursos da linguagem e ainda assim ser mais rápido do que o Ruby interpretado
    • Eu uso eval com frequência
      Talvez desse para não usar, mas para mim ele é mais ergonômico
    • Na minha experiência, os casos interessantes são eval, exec, define_method e o padrão de criar novas classes com Class.new e Struct.new
      A maior parte desses usos se concentra no boot da aplicação ou enquanto arquivos estão sendo carregados com require, o que em certo sentido já é parecido com uma etapa de compilação
  • Isso foi apresentado agora há pouco pelo Matz na RubyKaigi 2026
    É experimental, mas foi feito em cerca de um mês com ajuda do Claude, e a demo ao vivo deu certo
    O nome veio do novo gato do Matz, e o nome do gato veio do gato de Card Captor Sakura, que por sua vez faz par com uma personagem chamada Ruby

    • Muita gente fala de IA criando programas completos do começo ao fim, mas me parece que o cenário mais realista é transformar um programador 10x em um programador 100x
      No caso de alguém como o Matz, talvez seja mais como levar de 100x para 500x
    • Na minha cabeça, a referência mais recente de Spinel era Steven Universe, então eu não tinha percebido de jeito nenhum o trocadilho Spinel/Ruby (Moon); agora que entendi, meu dia ficou melhor
    • Eu naturalmente achei que fosse sobre o mineral espinélio :)
      https://en.wikipedia.org/wiki/Spinel
    • Obrigado
      Parece que o vídeo ainda não está ao vivo, e eles vão subindo um por um neste canal
      https://www.youtube.com/@rubykaigi4884/videos
    • Essa história da origem do nome do gato parece meio suspeita quando se pensa no drama do Ruby Central e na relação com os fundadores da Spinel.coop
      O nome do projeto também dá a sensação de ter sido escolhido de forma emocional
  • Sem dúvida é muito impressionante, mas parece impossível de manter sem um agente de IA
    spinel_codegen.rb tem 21 mil linhas, e alguns métodos chegam a 15 níveis de aninhamento
    Código de compilador já tende a ser difícil de deixar bonito, mas isso parece muito complicado de manter por humanos até mesmo para esse padrão

    • Código de compilador pode ficar bem bonito se houver tempo suficiente
      Compiladores têm fronteiras de subsistemas bem definidas e handoffs claros entre etapas, então, na verdade, estão entre as coisas mais fáceis de modularizar
      O problema costuma ser fazer funcionar primeiro e depois nunca sobrar tempo para refatorar, e aí a sujeira só vai crescendo
    • spinel_codegen.rb está quase no nível de um horror lovecraftiano
      Quando uso Claude, meu código sempre acaba virando esse tipo de espaguete, então eu estava me perguntando se estava fazendo algo errado
      Mas ver qualidade de código bem ruim em vários pontos até num projeto realmente interessante feito por alguém que considero um programador de altíssimo nível me mostrou que não sou só eu
      Por exemplo, infer_comparison_type() não é o pior caso e nem é ilegível, mas existe uma implementação muito mais simples e clara, e o Claude não chega nela
      Se reunisse os operadores de comparação em um Set e tratasse com include?, ficaria mais curto, mais rápido, mais legível e mais fácil de manter
      Mas o Claude sempre cai numa cadeia de if-return, e até parece desconfortável até com if-else
      Minha base de código gerada pelo Claude também está cheia desse padrão, então agora sei que não sou o único
      Em compensação, os outros arquivos estão bem melhores, especialmente o diretório lib, que parece corresponder ao diretório ext do repositório principal do Ruby e tem qualidade razoável
      A API também é claramente influenciada pelo MRI Ruby, e mesmo que a implementação seja bem diferente, parece que o Matz guiou para que ela lembrasse parte da API original, então a saída ficou mais organizada
      [1] https://github.com/matz/spinel/blob/98d1179670e4d6486bbd1547...
    • Nesta fase, não acho tão importante se humanos conseguem manter isso manualmente
      Se os testes e benchmarks passarem, já fico satisfeito por enquanto
      Ainda assim, fico em dúvida se arquivos gigantes também são fáceis para IA lidar
      Eu tento manter arquivos abaixo de 300 linhas e acho que código fácil para humanos entenderem também deve ser mais fácil para agentes de código
  • As restrições parecem ser estas
    Sem eval: eval, instance_eval, class_eval
    Sem metaprogramação: send, method_missing, define_method (dinâmico)
    Sem threads: Thread, Mutex (Fiber é suportado)
    Sem encoding: suposição de UTF-8/ASCII
    Sem cálculo lambda geral: -> x { } profundamente aninhado com chamada de []
    A suposição de UTF-8/ASCII, pessoalmente, não me parece uma limitação tão grande, mas o restante parece ser uma restrição real para bastante programa
    E parece que dar suporte a isso de novo exigiria bastante trabalho

    • Isso remove uma boa parte da mágica do Ruby
  • Uso Ruby há muito tempo e já usei todos os recursos listados, e olhando por esse lado, o que eu acabei querendo com o tempo foi justamente uma versão assim de Ruby simples
    É mais simples e mais fácil de entender, mas ainda preserva a estética própria do Ruby
    Agora, com LLMs, a produtividade de geração de código é tão alta que já há menos necessidade de reduzir boilerplate com metaprogramação em nome da produtividade do desenvolvedor
    Isso porque o peso do código escrito manualmente pelo próprio desenvolvedor está diminuindo

    • Se o que você quer é apenas a estética do Ruby, Crystal também pode servir muito bem
      A sintaxe é parecida e há um sistema de tipos estático, o que leva a código compilado mais eficiente
    • Eu até acho melhor não ter eval, mas a ausência de threads e mutexes é uma pena
      A falta de define_method eu entendo pelo tipo de uso que ele tem
      Mas send e method_missing são comuns em bibliotecas existentes, e também não me parecem tão difíceis de implementar, por exemplo montando uma tabela de lookup em memória em tempo de compilação
      Então não sei se isso foi removido de propósito ou se simplesmente ainda não chegaram lá
      Espero que seja a segunda opção, mas ao menos por enquanto a compatibilidade deve impedir uso em produção
    • A vantagem da metaprogramação nunca foi escrever menos código
      Sempre foi reduzir a quantidade de código que precisa ser lida
  • Isso é muito legal, e eu espero há muito tempo por um compilador AOT para Ruby
    Só é uma pena não haver fallback para eval ou metaprogramação, mas imagino que a ideia tenha sido focar num subconjunto pequeno e de alto desempenho
    Eu gostaria que gems feitas com esse compilador AOT interagissem bem com o MRI
    Empacotar ou fazer bundle do Ruby padrão com gems ainda depende de tebako, kompo, ocran, e antes também havia projetos como ruby-packer, traveling ruby e jruby warbler
    É bom ter mais uma opção, mas continuo torcendo por uma solução definitiva com UX melhor para desenvolvedores

    • Sim, eu também tive que fazer um fork do warbler recentemente
      Fazia tempo demais que ele não recebia atualizações
  • Fico curioso sobre o motivo de não haver threads
    O scheduler do Ruby e a implementação subjacente em pthread parecem coisas que poderiam funcionar bem também no lado C, então me pergunto se a ideia era buscar dependência zero
    Se não houver plano de adicionar isso como extensão opcional depois, ou se não for algo apenas ainda não implementado, essa escolha parece meio estranha

    • Ainda não vi evidência de que tenham decidido deliberadamente não dar suporte a isso
      Acho mais provável que simplesmente ainda não tenham chegado lá
      Multithreading já é algo muito difícil de fazer direito por natureza
  • É surpreendente que isso tenha sido feito em pouco mais de um mês
    Pode-se dizer o que for sobre IA, mas nas mãos de um desenvolvedor talentoso ela produz um ganho enorme de velocidade

    • A indústria inteira começa instalando agent harness, SOUL.md, permissões, skills, MCPs, hooks, env e tudo mais
      Já o Matz parece funcionar só com gem env|info e find
  • Como isso foi feito pelo próprio Matz, fico curioso sobre o quão realista é a chance de isso virar parte do core do Ruby no futuro
    E, se isso acontecer, também me pergunto o quanto isso seria uma ameaça para o Crystal

    • Crystal tem um sistema de tipos estático explícito e foi otimizado para compilação AOT no nível da linguagem
      Essas características são praticamente indispensáveis para compilar e manter programas grandes
      Já isso aqui é voltado a um subconjunto limitado de Ruby, então a maioria dos gems populares de Ruby provavelmente não vai rodar como está
      Como subconjunto de linguagem voltado a compilar para C, isso parece mais próximo de PreScheme
      Neste estágio, eu não diria que os dois estão competindo diretamente no mesmo espaço
      Ruby completo quase certamente vai precisar de JIT
      [1]: https://prescheme.org/
    • Por outro ângulo, parece que no fim chegaremos ao ponto em que LLMs vão despejar uma especificação formal em qualquer linguagem que quisermos
      Seria a revanche de ferramentas como Rational Unified Process e Enterprise Architect
      A diferença é que, no lugar de diagramas UML, viriam arquivos markdown
  • Isso parece útil para o lado de ferramentas de infraestrutura
    Por exemplo, dá para imaginar um bundler escrito em Ruby, mas compilado estaticamente, que também cumpra o papel de ferramenta de instalação do Ruby como o RVM
    Os buildpacks Ruby atuais são escritos em Ruby, mas exigem bootstrap com bash, o que é irritante e cria edge cases
    O CNB foi escrito em Rust para evitar esse problema, e a ideia de distribuir um binário único sem dependências é realmente muito poderosa