Onde dois princípios se contradizem
Nove tensões reais: a escolha, o motivo, o custo aceito e o arquivo onde a decisão mora. Uma lista de princípios diz o que se quer; a tensão diz o que se escolheu.
Um princípio isolado não informa nada. Todo mundo é a favor de segurança, e todo mundo é a favor de velocidade.
O que informa é onde dois princípios se contradizem e qual deles venceu — e essa decisão, nesta linguagem, está sempre num arquivo.
adopt Arcane.Principios as Prin
// A tensao e o conteudo: a lista diz o que se quer, a tensao diz o que
// se escolheu quando nao era possivel querer as duas coisas.
ts := Prin.tensoes()
assert len(ts) bigger_eq 9
cycle t in ts:
assert len(t["entre"]) is 2
assert t["escolha"] is not ""
assert t["custo"] is not "" // toda escolha tem preco declarado
out $"{len(ts)} tensoes, e cada uma aponta um arquivo"Segurança × verificação: o aviso que não virou erro#
Duas threads escrevendo na mesma variável perdem atualizações em silêncio — medido: 40.425 de 80.000. Numa rota do Kiln é pior, porque a concorrência é invisível: seis pedidos simultâneos numa rota que lê, espera e escreve entregaram 1 de 6.
O check avisa. Ele não recusa.
E a lista de métodos que disparam o aviso foi medida, não presumida: append de quatro threads, 5 mil vezes cada, entregou 20.000 de 20.000 — o GIL protege a operação inteira, e avisar sobre ele seria falso alarme em código que funciona.
Verificação × falso alarme: o analisador cala#
A calibragem é 0 erros em 222 arquivos conhecidamente bons. Quando o analisador não consegue provar, ele fica calado — e a lista de silêncios é explícita.
| Cala quando | Porque |
|---|---|
| o outro arquivo não compila | um falso alarme no caminho mais comum de um projeto modular ensina a desligar a verificação |
| há ciclo de import | a leitura não termina, e chutar seria pior |
| a profundidade (4) acaba | o custo cresce e a certeza não |
o relay nomeia algo que só existe em execução | não há como ler o que ainda não rodou |
v["k"] ?? padrao | ?? é exatamente o que a dica daquele erro recomenda — acusar o próprio conserto desligaria a ferramenta |
um parâmetro de tipo (T) chega com cara de tipo | sem isso, a trilha ganhava dois alarmes no capítulo que ensina generics |
Velocidade × depurabilidade: o depurador desliga o compilador#
interp.compilar_corpos = False. O depurador para em cada linha sombreando execute, e o corpo compilado passa por fora.
Um depurador que enxerga metade das instruções é pior que um interpretador mais lento: ele mente sobre onde o programa está.
Velocidade × correção: o escopo do laço#
Reaproveitar o escopo entre voltas de um laço é a otimização mais rentável do interpretador. E é a mais perigosa: errá-la não dá erro, dá resposta errada.
acoes := []
cycle i from 1 to 3:
acoes.append(lambda => i) // cada volta tem o SEU 'i'
assert acoes[0]() is 1
assert acoes[1]() is 2
assert acoes[2]() is 3 // e nao 3, 3, 3
out "cada closure lembra a volta em que nasceu"_corpo_captura_escopo varre a árvore inteira, e não só as instruções — um lambda vive dentro de uma expressão. Sem isso, as três closures veriam todas o último valor: o clássico que o Python tem e que aqui não acontece.
Extensibilidade × nomes bons#
route, render, server, agrupar e ordenar são nomes bons demais para tirar de quem escreve. Por isso palavra nova entra como contextual, e não em KEYWORDS.
// 'route' e contextual: aqui e um nome comum
route := "/pedidos"
agrupar := yes
assert route is "/pedidos"
assert agrupar is yes
out "as palavras do framework continuam livres"| Família | Quantas | Onde valem |
|---|---|---|
| Kiln | 11 | dentro de server e de uma rota |
| OOP / blueprint | 21 | onde um modificador faz sentido |
type, opaque, where | 4 | quando a linha confirma a declaração |
| Crucible | 10 | numa suíte de teste |
| verbos de quadro | 6 | logo depois de um >> |
Runtime modular × zero dependência#
A biblioteca padrão usa apenas a biblioteca padrão do Python. Isso significa código escrito à mão onde havia biblioteca madura:
- ChaCha20-Poly1305, pelo RFC 8439
- o
.xlsx, sem dependência externa - o WebSocket, pelo RFC 6455 — máscara, ping, pong, continuação e quadro de 64 bits
- os gráficos da Vitrine, em SVG escrito no servidor, com ~4 KB de cliente
O preço está escrito: criptografia e formato de arquivo implementados aqui, com o risco que isso tem. E o ganho também: um app em rede fechada funciona — que é onde painel de dados costuma rodar.
Portabilidade × performance#
A portabilidade é herdada do CPython. É o que dá Linux, macOS, Windows, ARM e ARM64 sem uma linha de código de arquitetura, e o que faz adopt Python.numpy existir.
É também o que põe o teto em ~6,5×. As duas coisas são a mesma decisão vista de dois lados, e não há como ficar só com uma.
Controle × segurança: onde a proteção para#
FFI sem ponteiro não é FFI. Arcane.C recusa o nulo e confere o layout da struct contra a ABI — e aritmética de ponteiro é aritmética de ponteiro.
Mensagem útil × identidade do erro#
O runtime fala português. A tradução acontece no desenho, nunca em error.message.
| Decisão | Sem ela |
|---|---|
| traduzir ao desenhar | e.message é o que um handle compara e o que milhares de testes comparam — traduzir ali mudaria o comportamento de programa já escrito |
| o que não tem tradução sai em inglês | ninguém traduz 530 mensagens numa tacada, e um erro é mais útil legível em inglês que ilegível em português |
| a suíte roda em inglês | um teste que afirma "Division by zero" checa a estrutura do relatório; deixar o idioma solto o faria reprovar a cada tradução nova |
| há um piso de cobertura | o fallback certo é também o que esconde o buraco: o que falta sai em inglês legível, e ninguém vê |
O que interessa a um programa é a identidade do erro, não o idioma dele. O que interessa a uma pessoa é o contrário — e as duas coisas caibem, desde que em camadas diferentes.