3 pontos por GN⁺ 2025-11-04 | 1 comentários | Compartilhar no WhatsApp
  • Um registro da análise do código C de 50 linhas do interpretador da linguagem K criado por Arthur Whitney, interpretando seu estilo de programação singular
  • O código inclui várias estruturas experimentais incomuns em relação ao C tradicional, como sintaxe compactada baseada em macros, extensões não padrão de C e uso implícito de argumentos
  • O autor interpreta diretamente o significado de cada macro e função, explorando a filosofia das linguagens da família APL e os prós e contras da densidade de código
  • Como vantagens do código, aponta-se a curta extensão e alta capacidade de composição; como desvantagens, a sintaxe não padrão e a perda de legibilidade
  • Em conclusão, esse código é avaliado como um exemplo que mostra não tanto como escrever de forma curta, mas sim a importância de uma forma de pensar que escreve o código somente depois de compreender completamente o problema

Arthur Whitney e seu código

  • Arthur Whitney é um cientista da computação que projetou as linguagens A, K, Q e os bancos de dados kdb, Shakti
    • kdb é um banco de dados de séries temporais ultrarrápido usado no setor financeiro, e Shakti é uma versão ainda mais rápida, projetada para processar conjuntos de dados na escala de 1 trilhão de linhas
  • Suas linguagens são linguagens baseadas em arrays fortemente influenciadas por APL, priorizando concisão e expressividade matemática
  • O foco do texto não está nas aplicações financeiras, mas em analisar o estilo singular do código C escrito por Whitney

A estrutura do interpretador K de 50 linhas

  • O repositório público ksimple inclui um interpretador em C de cerca de 50 linhas que Whitney escreveu em poucos dias
  • O núcleo do código é composto por dois arquivos, a.h e a.c, e se caracteriza pela abreviação de definições de função por meio de macros e por uma estrutura que usa ponteiros como se fossem inteiros
  • A instrução typedef char*s,c; define s como ponteiro para string e c como tipo caractere
  • s Q=(s)128; é um exemplo de uso de ponteiro como inteiro; ao longo de todo o código, Q é usado como um valor especial que representa estado de erro
  • São usadas várias extensões de sintaxe do GCC, como statement expression na forma ({e;}) e o operador ?:

O significado das principais macros e funções

  • #define _(e...) ({e;}) : macro que agrupa várias instruções em uma única expressão
  • #define i(n,e) : expressão abreviada de repetição, representando um loop for em uma linha
  • #define Q(e) e afins são macros de tratamento de erro; Qr, Qd, Qz retornam erros de rank, domain e not-yet-implemented, respectivamente
  • As macros _s, _i, f, F simplificam declarações de função e usam implicitamente os argumentos x e a
  • ax, ix, nx etc. são macros de verificação de tipo de dados e indexação; ax determina se “x é um átomo (atom)”
  • f(w,write(1,ax?&x:x,ax?1:strlen(x));x) é a função de saída: se for átomo, imprime como caractere; se for vetor, como string

Como o interpretador funciona

  • A função m(x) faz alocação de memória e gera um ponteiro com informação de comprimento incluída; o comprimento máximo do vetor é 255 bytes
  • A macro g(a,v) faz o tratamento unificado de operações sobre átomo/vetor, e funções como not, sub, At, _A são definidas com base nela
  • A macro G(f,o) faz a geração automática de funções de operadores binários, suportando operações como <, ==, +, *, &, |
  • cat, rev, cnt, Tak etc. são funções de manipulação de vetores; rev gera índices em ordem inversa usando a função ind
  • A função e() é um avaliador recursivo que lê a string da direita para a esquerda e processa variáveis de um único caractere, números e operadores
  • main() recebe entrada, avalia com e() e imprime o resultado em formato de laço REPL

Avaliação do estilo de código

  • Vantagens
    • Conjunto conciso de operações primitivas composto por macros combináveis
    • Como o código é curto, é possível entender toda a lógica de uma vez, sem rolagem
    • A expressão de alta densidade comprime a estrutura lógica do código
  • Desvantagens
    • Tratamento de tipos sem significado semântico, como usar char* como se fosse inteiro
    • Queda de legibilidade causada por uso direto de códigos ASCII, operadores ternários complexos e sintaxe não padrão
    • O uso implícito de argumentos e os nomes curtos de variáveis dificultam entender a intenção
  • Elementos neutros
    • A sintaxe exclusiva do GCC (?:, statement expression) é interessante, mas reduz a portabilidade
    • O uso implícito de argumentos pode ser útil em código pequeno, mas em código grande pode causar confusão
    • Nomes curtos podem ser eficientes depois que se ganha familiaridade, mas têm baixo poder de transmitir significado

Conclusão e lições

  • Esse código mostra não simplesmente como escrever de forma curta, mas uma forma de pensar que escreve o código somente depois de compreender completamente o problema
  • O código de Whitney é uma forma de transportar para o código um modelo matemático já concluído, ou seja, “um resultado de expressar o pensamento em código”
  • O autor reflete sobre seu hábito usual de tentar resolver o problema dentro do código e,
    daqui para frente, enfatiza a importância da modelagem conceitual e da organização do pensamento antes de escrever código
  • Em última análise, o experimento é resumido como uma experiência de treinar a “capacidade de ler código” e explorar o equilíbrio entre densidade de código e clareza de pensamento

Ideias para experimentos futuros

  • Propostas de prática para expandir o interpretador:
    • Suporte a vetores de ponto flutuante
    • Processamento de mais de 255 elementos
    • Números com vários dígitos e nomes de variáveis
    • Literais de array e ignorar espaços em branco
    • Adição de gerenciamento de memória e exibição de erros
    • Completar funções ainda não implementadas
  • Essas extensões podem se tornar um experimento de desenvolvimento para transformar a linguagem em algo realmente utilizável, mantendo o estilo de código à la Whitney

1 comentários

 
GN⁺ 2025-11-04
Comentários no Hacker News
  • Os macros deste código servem para compactar operações comuns Eu li primeiro o J Incunabulum e depois vi este código, mas para programadores acostumados com C que começam a ler do meio, as definições de macro do início podem causar confusão Como os macros se constroem uns sobre os outros, o código sobe rapidamente a escada da abstração Gosto especialmente do macro Iterate (i), que reduz loops verbosos a uma única letra O motivo de esse tipo de código denso ser difícil de ler é que ele cria dezenas de abstrações em poucas linhas e já as usa imediatamente Por isso é preciso ler devagar, uma letra de cada vez Para quem já trabalhou em grandes codebases compostas por centenas de arquivos finos, esse nível extremo de compactação até parece refrescante

    • Eu também tive uma impressão parecida ao ler o Incunabulum, mas quando troquei os nomes das variáveis por emojis ficou muito mais fácil de entender Como dá para ver na imagem do código na versão com emojis, parte do problema não é só a densidade de informação, mas também a ortografia Linguagens modernas não permitem usar símbolos ou emojis em identificadores, mas se essa distinção visual fosse possível seria bem mais fácil de ler Além disso, a maioria dos editores usa syntax highlighting por categoria sintática, mas às vezes coloração baseada em tokens (uma cor única para cada identificador) é bem mais útil O “hashed syntax highlighting” do Sublime Text é um exemplo disso Depois dessa mudança, a estrutura do código ficou visível de imediato
    • Parece que desenvolvedores até preferem codebases gigantes Eu gosto de uma estrutura em que dá para procurar tudo direto com grep *.[ch], sem subdiretórios Projetos Java em especial têm arquivos pequenos demais e com pouco conteúdo, então é difícil encontrar qualquer coisa Com uma IDE talvez fique melhor, mas eu não uso Whitney disse numa entrevista que queria colocar todo o código em uma página, e que sua “IDE” era o console do Windows e o Notepad
  • Para entender o código C de Arthur Whitney, primeiro é preciso aprender uma linguagem da família APL Caso contrário ele vai parecer apenas um estilo estranho de C Whitney está tentando usar C como se fosse APL O estilo sem espaços, com nomes de uma letra e funções de uma linha é o mesmo do APL É parecido com um programador de Pascal usando algo como #define begin {, mas Whitney é muito mais original do que isso

    • Mesmo do ponto de vista de um usuário de APL, isso parece estranho A linguagem K criada por Whitney usa esse estilo, mas funções de uma linha não eram possíveis no APL tradicional Macros, operador ternário e nomes implícitos de variáveis não existem em APL A essência do APL é a operação sobre arrays imutáveis, e o estilo em C de Whitney é diferente dessa filosofia
    • Sobre a frase “parece um programador de Pascal migrando para C e fazendo #define begin {”, alguém brinca: “ah, tipo Stephen Bourne”
    • No começo pareceu uma linguagem funcional, mas logo fez lembrar o horror do pré-processador de C
    • O próprio início do texto já explica que “o C de Whitney foi inspirado em APL” É uma crítica aos muitos comentários que apenas resumem o texto
    • Aprender J também pode ser uma boa ideia Ele é mais acessível que APL e usa símbolos que podem ser digitados em um teclado comum
  • Ao procurar por Shakti, vi que o link da Wikipedia redireciona para k.nyc, e a página tem apenas uma letra: ‘k’ Olhando o fonte, era literalmente só `k

` Isso parece uma versão em HTML do minimalismo ao estilo Whitney — remover tudo que é desnecessário e deixar o compilador cuidar implicitamente do resto

  • k

  • Este post de blog é uma excelente análise, independentemente da avaliação sobre o estilo de programação de Whitney Considerando que o autor o escreveu em 8 horas, há bastante profundidade, e a seção de conclusão foi especialmente marcante Link do original

  • Isso lembra a tentativa de Stephen Bourne de fazer C parecer Algol Dá para sentir uma vibe parecida vendo o exemplo em mac.h e o exemplo em expand.c

  • Toda área tem suas “best practices”, mas elas só funcionam bem para casos médios Em situações específicas, às vezes é melhor ir justamente na direção contrária No fim, a sabedoria coletiva serve como padrão inicial, mas quando você começa a pensar por conta própria, inevitavelmente passa a enxergar as brechas

    • Por isso eu não gosto da expressão “best practice” Na prática ela é só um meio-termo mediano É uma troca em que se sacrifica eficiência e desempenho para ganhar manutenibilidade e consistência
    • Fazer um bom produto e ter um codebase com legibilidade ou curva de aprendizado agradável são coisas separadas O fato de uma dar certo não faz a outra vir junto automaticamente
  • Gostei de ver uma visão equilibrada, sem agressividade em relação ao código Foi divertido de ler e pretendo reler depois

  • Fiquei curioso se esse estilo de programação é um paradigma específico Quase nunca vi código assim em projetos reais, exceto coisas como “business card ray tracer” O código-fonte da linguagem J criada por Whitney também tem um estilo extremamente compactado parecido

    • Sim, esse é o estilo de programação próprio de Whitney Ele aparece de forma consistente nos seus interpretadores de linguagens de array, e ele é famoso por colocar implementações inteiras em poucas páginas Há também um link para um meta-comentário reunindo discussões relacionadas no HN
    • Em resposta a “nunca vi esse tipo de código na prática”, alguém diz: “você teve sorte” Isso já não é mais C, mas uma nova linguagem criada em cima de C, algo como uma DSL interna C é apenas o primeiro alvo de compilação
    • É parecido com linguagens da família APL como J e K Elas usam símbolos não ASCII e conseguem colocar muita informação em uma página com densidade extrema Depois que você se acostuma, também há a vantagem de reduzir camadas de abstração
    • Há também um vídeo relacionado ao co-dfns feito com uma abordagem parecida Não é C, mas foi escrito em um estilo igualmente denso
    • Em tom de brincadeira, chamam isso de “OCC (Obfuscated C Code)”
  • Ao olhar para as seguintes definições de macro,

    #define _(e...) ({e;})
    #define x(a,e...) _(s x=a;e)
    #define $(a,b) if(a)b;else
    #define i(n,e) {int $n=n;int i=0;for(;i