Referência
O inventário canônico da linguagem: keywords, tipos builtin e decoradores. Serve a dois propósitos: ser a lista única do que mora no escopo global (o não-envenenamento da seção 1 em forma de tabela), e responder à pergunta que a contagem crua de decoradores provoca, “não são decoradores demais?”.
Keywords
Seção intitulada “Keywords”As palavras tecidas na gramática. São o escopo global irredutível: reservadas em todo programa, e por isso mantidas no mínimo.
- Declaração:
fnletvarmutconstdeclaliasunionmoduleuse - Controle de fluxo:
ifelsematchloopinbreakcontinuereturndefercatchyield - Concorrência:
spawntimeout - Compilação e segurança:
comptimeunsafeassertassume - Visibilidade:
pubpriv - Conversão:
as - Literais:
truefalse
Trinta e dois no total. O que parece keyword mas não é (e por quê):
type: não é keyword, é o kind (o tipo cujos valores são tipos, builtin, seção 10), e mora na lista de tipos builtin. Quem declara um tipo édecl;typeé o que você escreve quando algo é um tipo (T: type,-> type). Não existetype Nome = …: estrutura nova édecl, apelido éalias(seção 2).select: não existe; é omatchsem sujeito (seção 4). Um construto a menos para o mesmo poder.self: não existe; o receiver de um método tem nome livre (fn (d: *Dog) ...), e a auto-referência de um processo é o métodoruntime.self()(seção 3). Nenhum nome mágico reservado.null: não existe; ausência éOptional[T](seção 6), e oNULLdo C viraOptionalna fronteira (seção 17).and/or/not: a linguagem usa os símbolos&&/||/!.generator: é o decorador@generator(seção 11), não keyword.print/panic: não são keywords nem builtins; vivem emio/runtimee se importam (seção 1). O escopo global não carrega funções.
Tipos builtin
Seção intitulada “Tipos builtin”Os tipos que a sintaxe core pressupõe, disponíveis sem import porque a gramática os menciona (um Result no catch, um Channel no <-, um int num literal). É a lista fechada do que mora no escopo global; todo o resto é stdlib importada.
- Resultado e ausência:
Result[T, E](variantesOk/Err),Optional[T], e os conjuntos de erroerror{...}(seção 7) - Concorrência:
Channel[T](seção 4) - Numéricos: a família de largura arbitrária
iN/uN(1 a 65535) e os apelidosint/uint/isize/usize/byte/bit(byte=u8,bit=u1); a família de ponto flutuantef16/bf16/f32/f64/f128(apelidofloat);bool;noreturn(o tipo bottom da divergência) (seção 14) - Texto:
string, e as unidades de iteraçãobyte/codepoint/grapheme, comcharcomo apelido degrapheme(seção 16) - Agregados:
[N]T(array de tamanho fixo) e[]T(slice) - Ponteiros:
*T(ponteiro-de-um) e[*]T(ponteiro-de-muitos, N contíguos que se possui, base de coleções, seção 6); os handles de alocaçãoPtr/RawPtrda camada de memória (seção 5) - Comptime:
typee o universo de proposiçõesprop(tipos e proposições são valores em comptime, seções 10 e 21);Generator[T](seção 11); e o operador-de-tipodual, que espelha um protocolo de sessão (seção 21) - Tempo:
Duration(ou64de nanossegundos dotimeout, seção 14)
O que não é builtin, apesar de parecer fundamental: as coleções List/Map/Set (pacote collections), as interfaces Display/Serializable/Iterator/Writeable (fmt/encoding/io), os gerenciadores MemoryManager/MemorySource (pacote mem), as durações de precisão arbitrária Duration[T]/ArbitraryDuration (time), as máquinas de prova e tática (Eq/Refl e a library Goal/Stack/tática da seção 21, tudo Makoto sobre as primitivas de prova), e toda função (print em io, panic em runtime, reflect/fail em compiler, size_of/align_of/offset_of em mem). A linha é deliberada: builtin é só o que a sintaxe não consegue expressar sem; o resto se importa, e quem não usa não paga.
Decoradores, por domínio
Seção intitulada “Decoradores, por domínio”Keyword é conceito do core; decorador é etiqueta de subsistema. A divisão entre as duas categorias não é estética, é o que cada uma significa. Uma keyword é um conceito do núcleo, um ato que todo programa exerce (definir, comutar, repetir, declarar): o vocabulário comum. Um decorador é a etiqueta do subsistema a que algo pertence: @mm diz “isto é memória”, @supervisor diz “isto é concorrência”, @cimport diz “isto é FFI”. É por isso que a contagem crua assusta e não devia: você nunca encara os quarenta de uma vez, você encara os do subsistema em que está mexendo. O decorador não é ruído de sintaxe, é o carimbo de fronteira que diz em que sistema você entrou (seção 1).
A contagem crua assusta, são quarenta. Mas a contagem crua é a métrica errada, porque decoradores se agrupam por domínio, e um programa toca um ou dois domínios, nunca os quarenta. O que pesa não é o total no manual, e sim quantos você encontra na tarefa à frente. Agrupados:
- Memória (6):
@mm@transfer@promote@pin@unpin@limit. Alocador, posse e movimento (seção 5). É opt-in: com o GC default, você não escreve nenhum, porque são a superfície de quem desce para@mm(none)/arena. - Contratos (2):
@requires@ensures. Pré e pós-condições verificadas (seção 5). Aparecem só onde você quer a checagem. - Concorrência e resiliência (2):
@supervisor(árvores de supervisão, seção 8),@register(registro nomeado de processos, único, ou em grupo via@register(name, group), seção 3). - Composição (1):
@embeds. Promoção de métodos e campos (seção 2). - FFI com C (4):
@cimport@extern@callback@repr. A fronteira com C (seção 17). Um programa puro nunca os digita. - Assembly (1):
@asm. Arquitetura e dialeto na função (@asm(x86, intel)) e binding de registrador no param ou local (@asm(in, rax)); asm inline (seção 18). Nicho do nicho. - Reatividade de UI (4):
@state@derived@effect@context. Estado reativo (seção 20). Só existem em.mkoui, a extensão que um.mkocomum não ativa. - Estrutura de UI (6):
@component@server@client@jsimport@css@scope. Componentes, fronteira servidor/cliente, estilo escopado (seção 20). Também só em.mkoui. - Testes (3):
@test@testmode@bench. Teste, mocking e benchmark (seção 1). - Generators (1):
@generator. Funções que produzem poryield(seção 11). - Disciplina de posse (2):
@must_consume@consume_once. Linearidade e afinidade nível-de-tipo (seção 21). Opt-in: só um recurso que você quer que o compilador rastreie exatamente-uma-vez/no-máximo-uma-vez os carrega. - Refinamento (1):
@where. Um predicado num tipo (seção 21). Aparece só nos tipos que você restringe. - Cercas (2):
@pure@total. Promessas de efeito e terminação (seção 21). Inferidas por default; você as escreve onde demanda a checagem, ou onde uma função comptime entra num tipo. - Sessões (3):
@protocol@sends@receives. O protocolo de um canal e seus passos (seção 21). Só umChanneltipado por um@protocolos vê; um canal comum nunca. - Prova (1):
@proof. A cerca que torna uma família indexada ou função em lógica confiável (seção 21). Nicho do nicho: só um kernel provado o carrega. - Model checking (1):
@spec. Safety e liveness de um design de processos (seção 21); uma extensão, como as de UI. Mora ao lado do@supervisor, e um programa sem ele nunca o vê.
O agrupamento é a resposta à “morte por mil decoradores”: eles não chovem juntos. Um serviço de rede em GC toca talvez @supervisor e @register, dois. Quem desce para memória manual ganha os seis de memória, e nada de UI. Quem escreve UI ganha os dez de .mkoui, e nenhum de asm. As quatro portas de C e a porta de asm a maioria nunca abre. A densidade que você sente é a do seu domínio, e cada domínio tem uma conta pequena. É o opt-in (seção 1) aplicado à anotação: a sofisticação fica disponível, agrupada e fora do caminho até você convocá-la.
Notas de implementação (lembretes)
Seção intitulada “Notas de implementação (lembretes)”Anotações de implementação, não de design: escolhas de como construir, não de o que a linguagem é.
- Frontend em Go. O lexer, tokenizer e parser provavelmente em Go, o que abre uma porta concreta: usar o TypeScript Compiler que a Microsoft reescreveu em Go pra ler os
.d.tsdo@jsimport(seção 20), em vez de reimplementar o type-checker do TS do zero. - Backend LLVM agora, próprio depois (seção 18), pragmático pros múltiplos alvos e o cross-compile.
- Calling convention própria depois (seção 23): começamos herdando a do LLVM/C (interop grátis, sem duas convenções a manter); uma convenção interna otimizada vem junto do backend próprio.