Pular para o conteúdo

Racional · ensaio 00

Por que Makoto

rationale.md · 85 linhas · 4 min de leitura

A tese. Por que mais uma linguagem de sistemas, quando já existem Rust, Go, Zig e a BEAM.

“Linguagem de sistemas” costuma significar “linguagem que mexe com o metal”: ponteiros, layout, syscalls. Mas há uma segunda leitura, e é dela que Makoto parte. Uma linguagem de sistemas é uma linguagem que se reconhece feita de vários subsistemas (execução, tipos, memória, concorrência, erros), cada um com suas próprias “cores”, e cujo trabalho é gerenciar as fronteiras entre eles.

A tese cabe em três verbos: Rust vaza, Go funde, Makoto separa.

  • Rust vaza. Os reinos sangram um no outro. async não fica no reino da execução: colore o sistema de tipos e escapa para toda assinatura. Lifetimes infectam funções que nem tocam o problema que elas resolvem. O resultado é que você passa o tempo desfazendo o que vazou em vez de compor. Excesso de acoplamento entre subsistemas.
  • Go funde. Não há reinos separados; há um sistema só. É simples enquanto cabe, mas estender força mexer em tudo, porque não existe um reino isolado para crescer (genéricos chegaram anos depois, e doeram). Ausência de subsistemas.
  • Makoto separa. Reinos isolados, com fronteiras neutras. O pecado a evitar é a cor de um reino manchar outro. Quando a cor fica confinada ao seu reino, a linguagem ganha três propriedades de uma vez: o core fica sagrado (nenhum reino força mudança em outro), a linguagem é extensível por subsistema (cresce um reino sem tocar os demais), e um reino futuro entra sem reescrever os que já existem. É a aposta numa frase: subsistemas que se compõem porque nunca se mancham.

A métrica que decide se uma feature merece existir é o teste do opt-in: você só paga pelo que convoca. Um conceito é caro não pela sua complexidade interna, mas se quem não o usa ainda precisa entendê-lo. unsafe em Makoto é barato porque vive em ilhas pequenas, e quem não faz FFI nunca o vê. Lifetimes em Rust são caras porque vazam para toda assinatura, então até quem escreve código trivial paga. O teste filtra: a linguagem pode ser consistente sem ser simples, rica onde você entra e invisível onde você não entra.

As quatro inspirações não são equitativas. Duas são positivas, duas são contra-exemplos:

  • BEAM / Erlang (positiva): a filosofia de reinos isolados levada à concorrência, com processos que não compartilham nada, supervisão e let it crash. É a maior herança estrutural (a seção de concorrência é a mais longa do doc).
  • Zig (positiva): o compilador como ferramenta e não mágica, com comptime, allocators como interfaces e FFI que lê o header. E a separação MemorySource (de onde vêm os bytes) × @mm (que estratégia os governa) é o desacoplamento do Zig levado um nível adiante.
  • Rust (contra-exemplo): mostra o custo do vazamento. Makoto quer a garantia de segurança de memória do Rust sem o borrow checker infectando tudo.
  • Go (contra-exemplo): mostra o custo de fundir. Makoto quer a leveza de Go sem a impossibilidade de estender.
  • Por que não “só usar Rust”? Porque o preço do Rust é pago por todos, sempre, e o teste do opt-in o reprova. A segurança de memória do Rust é real, mas vem amarrada a um modelo (lifetimes, &T/&mut T) que colore o programa inteiro. Makoto recupera a garantia por outra via (cap. 02).
  • Por que não “só usar Go”? Porque “um sistema só” não tem onde crescer. Faltam os reinos.
  • Por que não a BEAM (Elixir/Erlang)? Porque a BEAM é interpretada/dinâmica e não desce ao metal; Makoto quer a resiliência da BEAM em uma linguagem compilada, tipada, de sistemas.

O programador iniciante de Rust que precisa entender lifetimes para escrever código que nem os toca. O time de Go que descobre, anos dentro do projeto, que adicionar genéricos significava mexer na base da linguagem. O usuário de Zig que mistura PageAllocator/HeapAllocator/StackAllocator no mesmo nível e perde a separação entre “de onde vem a RAM” e “como ela é gerenciada”. Cada uma dessas dores é um reino que vazou, ou um reino que faltou.

Subsistemas que se compõem porque nunca se mancham. Uma assinatura de função diz o que ela faz, nunca como ela roda. E você só paga pelo que convoca.

A separação tem um custo nomeado: alguns contágios são deliberadamente mantidos. unsafe é contagioso (chamar unsafe exige contexto unsafe), mas isso é coloring de contrato, não de implementação. Ele te informa de um perigo real, e, diferente do async, pode ser contido (qualquer função que cumpra as pré-condições absorve o perigo e expõe interface segura por cima). A linguagem não finge que o perigo não existe; ela o confina. O nome Makoto (誠, “verdade”) aponta para exatamente isso: não para um subsistema, mas para a filosofia inteira.

Próximo: 01 · Filosofia