Tipos
A redefinição: inteiros de largura arbitrária,
declunifica struct/enum/interface, satisfação estrutural, e dois despachos (vtable vs monomorfização) escolhidos por necessidade.
O conceito
Seção intitulada “O conceito”Um sistema de tipos faz três trabalhos: descrever dados, descrever contratos, e decidir como
chamadas são despachadas. As linguagens mainstream tomam um punhado de decisões aqui que Makoto
revisita: larguras fixas (i32/i64), keywords separadas (struct/enum/interface/trait),
satisfação declarada (impl Trait for T), e uma estratégia de despacho fixa.
Como Makoto redefine
Seção intitulada “Como Makoto redefine”- Inteiros de largura arbitrária:
iN/uNpara qualquerNde 1 a 65535 (u7,i128,u777).byteéu8,bitéu1, unificados, a mesma coisa conceitual. A largura mora no tipo e documenta a intenção (“isto cabe em 7 bits”), em vez de ser uma decisão acidental herdada do hardware. declunifica struct, enum e interface: uma keyword, e o corpo desambigua (campos struct; variantes enum; assinaturas interface). São o mesmo ato (declarar um tipo) no mesmo reino.- Satisfação estrutural: se um tipo tem os métodos que a interface exige, ele a satisfaz. Não há
implements/impl. O tipo não precisa saber de antemão quais interfaces vai satisfazer. - Dois despachos, escolhidos por necessidade: valor-de-interface vtable (um par dado+vtable,
montada pelo compilador por tipo, erased); constraint genérica (
T + Trait, HKT) monomorfização (especialização estática). E a régua estrita de constraint:+= implementa interface,:= pertence a uma whitelist. Dois símbolos porque são duas perguntas diferentes.
O raciocínio
Seção intitulada “O raciocínio”Por que decl unifica três mas não a union? Pela regra de “operação + reino, não forma”
(cap. 01). Struct/enum/interface têm corpos de formato diferente e mesmo assim fundem, porque são o
mesmo verbo (declarar tipo) no mesmo reino (o sistema de tipos). union tem corpo idêntico ao da
struct e mesmo assim fica de fora, porque é outra operação (reinterpretar bytes) em outro reino (o
unsafe). Unificar union pela semelhança de superfície seria apagar uma fronteira.
Por que satisfação estrutural? Porque desacopla. A implementação não precisa conhecer a interface
para satisfazê-la: você cria um tipo, e mais tarde alguém descobre que ele serve onde a interface era
esperada. Some o ritual de impl (e o erro barulhento de esquecê-lo), e a validação acontece no
ponto de uso.
Por que dois despachos em vez de um? Porque cada um resolve o que o outro não consegue. A vtable
serve quando a ação não devolve o tipo concreto (w.write(...)): um ponteiro gordo uniforme, custo no
ponto de uso, zero overhead por objeto. Mas quando o resultado depende do tipo, como em map[A,B](xs: C[A]) -> C[B], que abstrai sobre o construtor C, a vtable não basta; é preciso monomorfizar. A
régua: ação que não devolve o tipo do receiver vtable; transformação que devolve monomorfização.
Por que dois símbolos de constraint? Porque um nome não distingue “pertence ao conjunto Foo” de
“implementa a interface Foo”. : introduz só whitelist ({List, Set}, pertencimento); + introduz só
interface (+ Writeable, implementação). Dois símbolos porque são dois eixos, e fundi-los reabriria a
ambiguidade que a explicitude quer matar.
Por que não as alternativas
Seção intitulada “Por que não as alternativas”- Larguras fixas (
i32/i64). Forçam a decisão de capacidade para dentro do código do usuário e não documentam intenção;i7diz o queintesconde. uniondentro dedecl. Operação e reino diferentes (cap. 01); fundir apagaria a fronteira unsafe.impl Trait for Texplícito (Rust). Acoplamento e ritual; esquecer oimplé um erro comum e barulhento. Estrutural remove o passo.- Function pointers inline na struct (Zig puro). Inflariam cada instância; a vtable por-tipo compartilha, mantendo o objeto magro.
- HKT de ordem superior arbitrária (Scala/Haskell). Aridade ≤ 2 (
C[_],C[_,_]) cobre a maioria do FP útil; permitir transformadores de monad abriria o abismo de inferência de kind. Poderoso sem ser footgun.
A dor concreta
Seção intitulada “A dor concreta”O i32 que silenciosamente transborda porque ninguém decidiu se cabia. O impl esquecido em Rust e o
erro de trait-resolution que aparece três camadas de instanciação abaixo, “candidate #3 has wrong
return type”. O objeto Zig que engorda porque carrega os próprios ponteiros de método. Cada uma é uma
decisão de tipos que vazou custo para onde não devia.
O modelo mental
Seção intitulada “O modelo mental”O tipo diz exatamente o que é; a largura mora no tipo. Um
decldeclara dados ou contrato (o corpo decide); satisfazer é ter os métodos; o despacho é vtable quando a ação não devolve o tipo, monomorfização quando devolve.
A fricção aceita
Seção intitulada “A fricção aceita”A unificação carrega o decl de responsabilidade (o corpo precisa desambiguar três coisas), e a
satisfação estrutural troca a declaração explícita por validação no call-site: você não anuncia que
satisfaz, mas também não tem surpresa silenciosa, porque o compilador checa onde a interface é
exigida. E o HKT raso (aridade ≤ 2) deixa de fora os transformadores de ordem superior, expressividade
sacrificada conscientemente para não importar o inferno de inferência.
Próximo: 08 · Comptime e reflexão