1 pontos por GN⁺ 5 일 전 | 1 comentários | Compartilhar no WhatsApp
  • Converte código Ruby em binários nativos standalone, visando execução com média geométrica cerca de 11,6x mais rápida que o miniruby do CRuby mais recente por meio de inferência de tipos em escala de programa inteiro e geração de código C
  • O pipeline de compilação transforma Ruby em texto AST com um parser baseado em Prism, depois um backend self-hosting faz inferência de tipos e geração de código C, e um compilador C padrão produz o binário standalone
  • O backend do compilador tem uma arquitetura self-hosting escrita em Ruby e, após o processo de bootstrap, gen2.c == gen3.c se mantém, fechando o loop de recompilar a si próprio
  • Inclui otimizações em tempo de compilação como achatamento de concatenação de strings, value-type promotion, loop-invariant length hoisting, static symbol interning e promoção automática para bigint, além de um engine de regexp embutido, bigint e runtime em header único para reduzir dependências externas de runtime
  • Não oferece suporte a eval, metaprogramação, Thread nem tratamento geral de encoding, mas demonstra a praticidade da compilação AOT para Ruby com um formato de distribuição que roda sem Ruby e grande diferença de desempenho em cargas computacionalmente intensivas

Como funciona

  • O pipeline de compilação funciona parseando arquivos Ruby, serializando-os em arquivos de texto AST, depois aplicando inferência de tipos e geração de código C, e por fim criando um binário nativo com um compilador C padrão
  • spinel_parse usa Prism e libprism para fazer o parse de Ruby e, quando o binário C não está disponível, usa um caminho alternativo com CRuby e a gem Prism
  • spinel_codegen roda como um binário nativo self-hosted, recebe o AST e realiza inferência de tipos + geração de código C
  • A etapa final compila o código-fonte C junto com o header do runtime com cc -O2 -Ilib -lm, e o binário resultante é gerado em formato standalone

Self-Hosting

  • A cadeia de bootstrap se fecha produzindo AST com CRuby + spinel_parse.rb, depois gen1.c e bin1 com CRuby + spinel_codegen.rb, e então usando o binário gerado para produzir gen2.c e gen3.c
  • gen2.c == gen3.c confirma que o bootstrap loop foi fechado
  • O backend spinel_codegen.rb é escrito em um subconjunto de Ruby que o próprio Spinel consegue compilar
    • classes, def, attr_accessor
    • if/case/while
    • each/map/select, yield
    • begin/rescue
    • operações com String, Array, Hash e File I/O
  • O backend não inclui metaprogramming, eval nem require

Desempenho e benchmarks

  • Os testes estão em 74 aprovados e os benchmarks em 55 aprovados
  • Em 28 benchmarks, a média geométrica é de cerca de 11,6x mais rápido que o miniruby do CRuby mais recente
  • A base de comparação é um build recente de miniruby do CRuby sem gems empacotadas; mesmo comparando com um baseline mais rápido que o ruby 3.2.3 do sistema, a vantagem continua grande em cargas computacionalmente intensivas
  • Desempenho computacional

    • life: 20ms contra 1.733ms, 86,7x mais rápido
    • ackermann: 5ms contra 374ms, 74,8x mais rápido
    • mandelbrot: 25ms contra 1.453ms, 58,1x mais rápido
    • versão recursiva de fib: 17ms contra 581ms, 34,2x mais rápido
    • nqueens: 10ms contra 304ms, 30,4x mais rápido
    • tarai: 16ms contra 461ms, 28,8x mais rápido
    • tak: 22ms contra 532ms, 24,2x mais rápido
    • matmul: 13ms contra 313ms, 24,1x mais rápido
    • sudoku: 6ms contra 102ms, 17,0x mais rápido
    • partial_sums: 93ms contra 1.498ms, 16,1x mais rápido
    • fannkuch: 2ms contra 19ms, 9,5x mais rápido
    • sieve: 39ms contra 332ms, 8,5x mais rápido
    • fasta: 3ms contra 21ms, 7,0x mais rápido
  • Estruturas de dados e GC

    • rbtree: 24ms contra 543ms, 22,6x mais rápido
    • splay tree: 14ms contra 195ms, 13,9x mais rápido
    • huffman: 6ms contra 59ms, 9,8x mais rápido
    • so_lists: 76ms contra 410ms, 5,4x mais rápido
    • binary_trees: 11ms contra 40ms, 3,6x mais rápido
    • linked_list: 136ms contra 388ms, 2,9x mais rápido
    • gcbench: 1.845ms contra 3.641ms, 2,0x mais rápido
  • Programas reais

    • json_parse: 39ms contra 394ms, 10,1x mais rápido
    • cálculo de bigint_fib com 1000 dígitos: 2ms contra 16ms, 8,0x mais rápido
    • ao_render: 417ms contra 3.334ms, 8,0x mais rápido
    • pidigits: 2ms contra 13ms, 6,5x mais rápido
    • str_concat: 2ms contra 13ms, 6,5x mais rápido
    • template engine: 152ms contra 936ms, 6,2x mais rápido
    • csv_process: 234ms contra 860ms, 3,7x mais rápido
    • io_wordcount: 33ms contra 97ms, 2,9x mais rápido

Recursos Ruby suportados

  • Como recursos Core, oferece suporte a classes, herança, super, mixins com include, attr_accessor, Struct.new, alias, constantes de módulo e open classes para tipos embutidos
  • Em Control Flow, oferece suporte a if/elsif/else, unless, case/when, pattern matching com case/in, while, until, loop, for..in, break, next, return, catch/throw e &.
  • Em Blocks, oferece suporte a yield, block_given?, &block, proc {}, Proc.new, -> x { }, method(:name), além de métodos com bloco como each, map, select, reduce, sort_by, times, upto e downto
  • Em Exceptions, oferece suporte a begin/rescue/ensure/retry, raise e classes de exceção definidas pelo usuário
  • Types inclui Integer, Float, String, Array, Hash, Range, Time, StringIO, File, Regexp, Bigint e Fiber
    • Valores polimórficos são tratados como tagged unions
    • Há tipos de objeto anuláveis T? para estruturas de dados autorreferentes
  • Global Variables compila $name como variáveis C estáticas e detecta incompatibilidades de tipo em tempo de compilação
  • I/O oferece suporte a puts, print, printf, p, gets, ARGV, ENV[], File.read/write/open, system() e crases

Strings, regexp, símbolos, Bigint e Fiber

  • Strings lidam tanto com strings imutáveis quanto mutáveis, e << promove automaticamente para a string mutável sp_String para fazer append in-place em O(n)
  • +, interpolação, tr, ljust/rjust/center e métodos padrão funcionam nas duas representações de string
  • Comparações como s[i] == "c" são otimizadas para acessar diretamente o array de chars, sendo processadas sem alocação
  • Concatenações como a + b + c + d são achatadas em uma única chamada sp_str_concat4 ou sp_str_concat_arr, reduzindo N-1 alocações
  • str.split(sep) dentro de loops reutiliza repetidamente o mesmo sp_StrArray, removendo 4 milhões de alocações em csv_process
  • Regexp usa um engine NFA de regexp embutido, sem dependências externas
    • Oferece suporte a =~, $1-$9, match?, gsub, sub, scan e split
  • Bigint usa inteiros de precisão arbitrária baseados em mruby-bigint
    • Há promoção automática em padrões de multiplicação em loop como q = q * k
    • É linkado como biblioteca estática e só é incluído quando realmente usado
  • Fiber oferece concorrência cooperativa baseada em ucontext_t
    • Suporta Fiber.new, Fiber#resume, Fiber.yield e passagem de valores
    • Variáveis livres são capturadas como células promovidas para heap
  • Symbols são implementados como um tipo sp_sym separado de strings
    • :a != "a" é preservado
    • Literais de símbolo são internados em tempo de compilação e viram constantes SPS_name
    • String#to_sym usa um pool dinâmico apenas quando necessário
    • Hashes com chaves símbolo usam sp_SymIntHash, armazenando diretamente chaves inteiras em vez de strings, eliminando strcmp e alocações dinâmicas de string

Gerenciamento de memória e value types

  • O gerenciamento de memória usa GC mark-and-sweep, incluindo free lists segregadas por tamanho, marcação não recursiva e sticky mark bits
  • Classes pequenas e simples são promovidas automaticamente a value types e colocadas na stack
    • Condições: até 8 campos escalares
    • sem herança
    • sem mutação via parâmetros
  • A alocação de uma classe com 5 campos, repetida 1 milhão de vezes, cai de 85ms para 2ms
  • Programas que usam apenas value types não exportam o runtime de GC

Otimizações

  • Com base na inferência de tipos em escala de programa inteiro, o compilador realiza várias otimizações em tempo de compilação
  • Value-type promotion transforma pequenas classes imutáveis em structs C alocadas na stack, eliminando overhead de GC
  • Constant propagation faz constantes literais simples como N = 100 serem inlined diretamente no ponto de uso, sem busca por cst_N
  • Loop-invariant length hoisting faz while i < arr.length calcular o tamanho apenas uma vez antes do loop
    • Se o objeto receptor for alterado no corpo, como com arr.push, esse hoist é desativado
  • Method inlining adiciona static inline a métodos curtos, não recursivos e com até 3 instruções, induzindo o inlining pelo gcc
  • String concat chain flattening reduz cadeias de concatenação a uma única chamada, eliminando strings intermediárias
  • Bigint auto-promotion promove automaticamente padrões de soma autorreferente ou multiplicação repetida para bigint
  • Bigint to_s usa mpz_get_str do mruby-bigint para processamento divide-and-conquer em O(n log²n)
  • Static symbol interning converte "literal".to_sym em constantes de tempo de compilação SPS_<name>; o pool de intern dinâmico só entra quando necessário
  • Em sub_range, strings com comprimento içado usam sp_str_sub_range_len para pular chamadas internas a strlen
  • line.split(",") dentro de loops reutiliza o sp_StrArray existente
  • Dead-code elimination usa -ffunction-sections -fdata-sections e --gc-sections para remover funções de runtime não usadas do binário final
  • Iterative inference early exit interrompe imediatamente o loop de ponto fixo quando os 3 arrays de assinatura de param, return e ivar deixam de mudar
    • A maioria dos programas converge em 1 a 2 iterações em vez de 4
    • O tempo de bootstrap cai cerca de 14%
  • parse_id_list byte walk troca s.split(",") por uma varredura manual com s.bytes[i] no parser de listas de campos do AST, chamado cerca de 120 mil vezes na self-compilation, reduzindo as alocações por chamada de N+1 para 2
  • O código C gerado mantém build sem warnings no nível padrão de alertas, e o harness usa -Werror para expor regressões imediatamente

Arquitetura

  • A estrutura do repositório se divide nos seguintes componentes
    • spinel: script wrapper de um comando só baseado em shell POSIX
    • spinel_parse.c: frontend C de 1.061 linhas, de libprism para AST em texto
    • spinel_codegen.rb: backend do compilador de 21.109 linhas, de AST para código C
    • lib/sp_runtime.h: header da biblioteca de runtime com 581 linhas
    • lib/sp_bigint.c: inteiros de precisão arbitrária com 5.394 linhas
    • lib/regexp/: engine de regexp embutido com 1.759 linhas
    • test/: 74 testes funcionais
    • benchmark/: 55 benchmarks
    • Makefile: automação de build
  • O runtime lib/sp_runtime.h reúne em um único header o GC, a implementação de arrays/hash/strings e outros suportes de runtime
  • O código C gerado inclui esse header, e o linker puxa apenas as partes necessárias de libspinel_rt.a
    • bigint
    • regexp engine
  • O parser tem duas implementações
    • spinel_parse.c linka diretamente com libprism e roda sem CRuby
    • spinel_parse.rb é o fallback em CRuby que usa a gem Prism
  • Os dois parsers produzem a mesma saída AST, e o wrapper spinel prioriza o binário C sempre que possível
  • require_relative é resolvido no momento do parsing, e os arquivos referenciados são inlined

Limitações

  • No eval: eval, instance_eval e class_eval não são suportados
  • No metaprogramming: send, method_missing e define_method dinâmico não são suportados
  • No threads: Thread e Mutex não são suportados; apenas Fiber é suportado
  • No encoding: assume UTF-8 e ASCII
  • No general lambda calculus: não lida com -> x { } profundamente aninhado nem chamadas []

Dependências e modelo de execução

  • As dependências de build são a biblioteca C libprism e CRuby para o bootstrap inicial
  • Não há dependências de runtime; os binários gerados exigem apenas libc + libm
  • Regexp usa engine embutido, então não requer biblioteca externa
  • Bigint é embutido, mas só é linkado quando realmente usado
  • Prism é o parser Ruby usado por spinel_parse
    • make deps baixa o tarball da gem prism do rubygems.org e extrai o código C em vendor/prism
    • Se a gem prism já estiver instalada, ela é detectada automaticamente
    • Também é possível indicar um caminho personalizado com PRISM_DIR=/path/to/prism
  • CRuby é necessário apenas no bootstrap inicial; depois de make, todo o pipeline roda sem Ruby

Histórico do projeto

  • Spinel foi implementado inicialmente em C, com 18K lines, ainda preservadas na branch c-version
  • Depois passou pela branch ruby-v1, reescrita em Ruby
  • O master atual é a versão reescrita em um subconjunto de Ruby capaz de fazer self-hosting

Licença

  • Usa a licença MIT
  • Segue o arquivo LICENSE

1 comentários

 
GN⁺ 5 일 전
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