Async e IO
A redefinição: async é colorless, e quem suspende é o processo, não a função. Não existe
async/await/Future.
O conceito
Seção intitulada “O conceito”Concorrência de IO exige que algo “espere sem travar tudo”. As linguagens mainstream resolvem isso
colorindo funções: async fn em Rust/JS/Python marca uma função como suspensível, e essa marca
propaga: quem chama uma async precisa ser async (ou await), até o topo. Nasce o “function
coloring”: metade da linguagem fica de uma cor, metade de outra, e as duas não se misturam.
Como Makoto redefine
Seção intitulada “Como Makoto redefine”Não há cor. Nenhuma função é async. O bloqueio em IO é transparente na sintaxe: você escreve
data := -> chan ou fs.read(...) como se fosse síncrono, e o processo suspende ali. O scheduler
pega outro processo enquanto este espera. Os pontos de suspensão são explícitos e poucos (operações
de io.*, send/recv de channel, o <-> síncrono), mas nenhum deles aparece como marca de tipo.
A consequência direta: paralelismo é spawn de processos, não composição de Futures. Para fazer
N coisas ao mesmo tempo, você spawna N processos e recebe os resultados por channel (cap. 04). Não há
Future/await/executor para gerenciar.
O raciocínio
Seção intitulada “O raciocínio”A pergunta de fundo é: a assinatura de uma função deve dizer como ela roda? A posição de Makoto é
não. Uma assinatura diz o que a função faz, nunca como ela é escalonada. “Roda de forma
suspensível” é detalhe de implementação, e detalhe de implementação não deve colorir o tipo. Essa é
a distinção que destrava tudo: coloring de contrato vs coloring de implementação. unsafe é
coloring de contrato (informa um perigo real que você precisa conhecer), e é aceitável. async é coloring
de implementação (vaza um detalhe de execução para o tipo), e é recusado. A diferença operacional sela o
veredito: async é incontível (a cor sobe infinitamente até o main); unsafe é contível
(qualquer camada pode absorver o perigo e parar a propagação). Uma cor que não se contém é exatamente o
tipo de mancha que a filosofia (cap. 01) existe para impedir.
Isso encaixa no modelo de memória e de concorrência sem costura: como o processo é a unidade de execução com uma única linha (cap. 02/04), “suspender o processo” é uma operação natural, e não precisa de uma máquina de estados de corotina exposta ao programador. O runtime faz o trabalho; a linguagem fica colorless.
Por que não as alternativas
Seção intitulada “Por que não as alternativas”async/await/Future(Rust/JS/Python). Coloring de implementação: infecta o sistema de tipos, força composição via blocosasync, e adicionaFuturecomo mais um tipo de primeira classe a gerenciar. Ganho real sobre “o processo suspende invisível”: nenhum.- Callbacks / promises. Inversão de controle, “callback hell”, máquinas de estado manuais. Pior ergonomia para o mesmo efeito.
- Threads de SO por requisição. Caras demais para o grão de concorrência que a BEAM-like quer (milhões de processos); e reabririam memória compartilhada (cap. 04 explica por que não).
A dor concreta
Seção intitulada “A dor concreta”O “what color is your function” clássico: você tem uma função síncrona perfeitamente boa e descobre
que precisa chamar algo async lá dentro. Agora ela tem que ser async, e quem a chama também, e
assim por diante, até você reescrever a árvore inteira ou manter duas versões de tudo. A cor que não
se contém custa retrabalho real, e não compra correção nenhuma que o modelo de processo não dê de
graça.
O modelo mental
Seção intitulada “O modelo mental”A unidade de suspensão é o processo. Você escreve IO como se fosse síncrono; o processo para, o scheduler segue. Bloqueio é fato, não marca de tipo.
A fricção aceita
Seção intitulada “A fricção aceita”Colorless não significa “tudo implícito”. O <-> (request-reply síncrono) exige timeout
explícito, uma marca obrigatória, ao contrário do <- silencioso. É uma assimetria deliberada:
deadlock entre dois processos que se esperam é estrutural, e o prazo é a saída honesta (cap. 04). E
shared-nothing tem custo de cópia/passagem de mensagem; Makoto aceita correção e distribuição-nativa
sobre throughput bruto de memória compartilhada.
Próximo: 04 · Concorrência