3 pontos por GN⁺ 2025-05-31 | Ainda não há comentários. | Compartilhar no WhatsApp
  • C3 é baseado na linguagem C e oferece recursos avançados como módulos, sobrecarga de operadores, genéricos e execução em tempo de compilação
  • Mantendo a sintaxe familiar de C, incorpora recursos que reforçam produtividade e segurança, como tratamento de erros, defer e foreach
  • A introdução de contracts declarativos e de tipos opcionais com um modelo próprio de tratamento de erros melhora a segurança e a clareza
  • Há suporte a um ambiente de desenvolvimento prático, com biblioteca padrão, integração com o sistema de build e alocação temporária de memória
  • Em build, criação de projetos e estrutura de código, há semelhanças com a linguagem Zig, sugerindo novos experimentos de design de linguagem

Visão geral e características do C3

O que é C3?

  • C3 é uma linguagem construída sobre a linguagem C, preservando uma sintaxe familiar e, ao mesmo tempo, oferecendo recursos difíceis de obter em C, como sistema de módulos, sobrecarga de operadores, genéricos, execução em tempo de compilação, tratamento de erros, defer, value methods, contracts graduais, slices, foreach e suporte a tipos dinâmicos
  • A estrutura de módulos usa namespaces para evitar conflitos de nomes (abc::Context, por exemplo, com namespaces explícitos)
  • O objetivo principal é aumentar a produtividade e oferecer recursos modernos de programação de sistemas com segurança

Características da linguagem

Exemplo Hello World

  • É sintaticamente semelhante a C
  • Na declaração de funções, é obrigatório usar explicitamente a palavra-chave fn
  • As funções da biblioteca padrão para entrada e saída são poderosas, e vários tipos também podem ser impressos diretamente

Loop foreach

  • Diferentemente de C, oferece suporte nativo à sintaxe foreach
  • Em laços com referência, usa-se & antes do nome da variável (recurso avançado)
  • Suporta break e continue, de forma semelhante ao foreach de outras linguagens

Loop while

  • Antes do C99 não era possível declarar variáveis dentro da condição do while, mas em C3 isso é permitido

enum e switch

  • O switch oferece suporte a break implícito (a mistura de break implícito e explícito pode dividir opiniões)
  • A palavra-chave nextcase permite mover-se explicitamente entre casos (facilitando a implementação de tabelas de salto)
  • É possível controlar o fluxo de switch-case de forma mais concisa do que em linguagens anteriores como Zig e C, onde isso era mais complexo

Palavra-chave defer

  • Ao final do escopo, os blocos reservados com defer são executados em ordem reversa, garantindo com segurança a liberação de recursos
  • Também há uso de defer em combinação com catch e try (controle de fluxo de tratamento de erros)

struct e union

  • Dentro de structs, são permitidos sub-structs/unions nomeados ou anônimos, o que facilita projetar o padrão tagged union
  • A distinção entre anônimos (incluindo duplicação de campos com o mesmo nome) e conflitos de nome é tratada de forma rigorosa

Modelo de tratamento de erros

  • O símbolo ? oferece suporte a tipos opcionais, unificando erros e valores opcionais para maior conveniência
  • Com a palavra-chave catch, é possível ramificar em caso de estado vazio (sem Optional) ou erro
  • Diferentemente de Rust e Zig, a distinção entre erro e valor opcional é mais fraca (vantagem: simplicidade; desvantagem: menor clareza de intenção)
  • O operador ! (rethrow) permite propagar exceções

Contracts

  • As pré e pós-condições de funções (Require/Ensure) são escritas entre <* .. *> (as condições são verificadas na compilação)
  • Há suporte até para análise de fold em tempo de compilação (análise estática ainda não implementada)

Métodos em struct

  • Usa métodos associados com anotação de tipo + notação por ponto (Foo.next), com namespace incluso (inclusive para tipos primitivos)
  • Permite métodos em todos os tipos, como struct, union e enum

Macros

  • Macros baseadas em avaliação em tempo de compilação (palavra-chave macro)
  • $ implementa parâmetros de tempo de compilação, e # permite passagem antes da avaliação
  • Estilo C (minimizando problemas de macros entrelaçadas, enfatizando estabilidade da AST, checagens com prefixo @ etc.)
  • Reflexão de tipos e execução em tempo de compilação são tratadas por macros

Propriedades de tipo

  • alignof, kindof, extnameof, sizeof, typeid, methodsof, has_tagof, tagof, is_eq, is_ordered, is_substruct etc.
  • Adequadas para metaprogramação e reflexão

Literais Base64/Hex

  • Permite declarar sequências de bytes diretamente no formato b64"..." e x"..."
  • Isso pode ser substituído pela macro embutida $embed (na prática, o uso é raro)

Tipos primitivos

  • Inclui vários tipos básicos como int, uint, char (sempre unsigned), bool, float, int128/uint128 etc.
  • Há tipos separados para ponteiros/tamanho, como iptr, uptr, isz e usz (um pouco menos intuitivos)
  • Diferentemente de C, o tamanho em bits é garantido

Outros

  • Traz um conjunto amplo de recursos como sobrecarga de operadores, subtipagem de structs, genéricos, runtime dispatch, tipo any e bitstructs

Prática: experiência com C3

Instalação do C3

  • Suporta tanto binários pré-compilados do site oficial quanto build direto do código-fonte
  • É necessário instalar LLVM e LLD (em caso de problema de linkedição, usar as flags de CMake -DLLVM_DIR e -DLLD_DIR)
  • Devido a problemas em algumas distribuições que não incluem bibliotecas do LLD, recomenda-se baixar os binários diretamente
  • O compilador C3 exige dependência de libtinfo

Criação de projeto

  • O comando c3c init gera a estrutura padrão de pastas (LICENSE/README.md/project.json/src etc.)
  • Organiza a base do projeto com Build, alvos de build e configurações de código-fonte (semelhante a Zig e Cargo)
  • O arquivo main.c3 padrão é bastante enxuto (opinião: adequado para novos usuários)

Criando uma calculadora

Design e objetivo

  • Implementar um parser recursivo descendente (Recursive Descent Parser) e a lógica central de uma calculadora para praticar vários recursos do C3, como funções, entrada/saída, gerenciamento de memória e laços
  • O objetivo é entender diretamente os pontos fortes e incômodos da linguagem, como a intuitividade da sintaxe e a produtividade no uso real

Tratamento de entrada

  • Usa alocador temporário (tmem) com @pool, liberando memória automaticamente ao final do escopo (arena allocator)
  • O modelo padrão de gerenciamento de memória oferece tmem (temporário) e mem (geral), além de um padrão de passar alocadores por função (misturando vantagens de Zig e C)
  • A função main deve declarar explicitamente o valor de retorno (exigido pelo compilador)
  • Funções cujo retorno pode ser ignorado recebem o atributo @maydiscard (evitando ignorar resultados de forma indevida)

Implementação do tokenizer

  • Decompõe a entrada do usuário em uma lista de tokens
  • Aproveita vários controles de fluxo da biblioteca padrão do C3, como List, sintaxe foreach e switch-case (nextcase, combinação de break implícito/explícito)
  • Há alguma confusão com a sintaxe de slices (os índices de ambas as pontas são inclusivos) e com slices de comprimento zero (há uma sintaxe separada para especificar o tamanho)
  • O uso misto de alocadores temporários/gerais mostra transparência e flexibilidade no gerenciamento de memória, com vantagens em relação a linguagens como Rust

Implementação do parser

  • Relato de experiência prática ao escrever o parser diretamente (omitido)

Conclusão e opinião geral

  • C3 busca o ponto de encontro entre linguagens de sistema tradicionais e design moderno
  • Foi projetada estudando Zig, Rust e C, com a meta de conciliar desempenho e estabilidade do código
  • Destacam-se recursos como modularidade, tratamento seguro de memória/erros/contracts, metaprogramação poderosa e sistema de build intuitivo
  • A curva de aprendizado é gradual para quem já tem experiência com C
  • O ecossistema ainda é imaturo, com language server, IDE e outros pontos a melhorar, além de algumas escolhas de sintaxe que podem dividir opiniões
  • Vale a atenção como uma linguagem alternativa de próxima geração para desenvolvimento low-level e de sistemas

Ainda não há comentários.

Ainda não há comentários.