Skip to content

Advanced pt

Enoch-199811 edited this page Aug 9, 2026 · 1 revision

English | 中文 | Русский | Español | Português | 繁體中文 | Deutsch

Avançado — Referências inteligentes, bibliotecas, memória e projetos reais

Masterclass: referências inteligentes tipadas, chamadas a bibliotecas C nativas, gerenciamento de memória, desempenho, anotações como ferramentas de design e um projeto prático completo.

Referências inteligentes tipadas

Uma referência inteligente é um valor tipado que aponta para um lvalue. Ela é declarada com permissão × nível × tipo base:

&<permission> <follow> <base type> <name> = &<lvalue>;
  • Permissões (7 combinações): r leitura, w escrita, m movimento (ponteiro), rw, rm, wm, rwm.
  • Níveis (4): u nível de programa (Unistream), f nível de método, a nível de escopo/área, t nível de thread.
  • Tipo base: int / double / float / string / char / arrays / classes — genérico.

Isso dá 7 × 4 = 28 tipos de referência.

Lendo, escrevendo, movendo

int counter = 0;
&w u int wr = &counter;          // writable program-level ref
Ref::write(wr, 10);

&r u int rr = &counter;          // read-only ref
CIO::println(get Ref::read(rr)); // 10

&rw u int rw = &counter;         // read-write
CIO::println(get rw);            // 10
rw = 5;
CIO::println(counter);           // 5

Movimento de ponteiro (permissão m)

Com m, a referência é um ponteiro móvel (como a++ em C):

ALL a = new int[3];
a[0] = 10; a[1] = 20; a[2] = 30;
&m u int mp = &a[1];
CIO::println(get mp);            // 20
mp++;
CIO::println(get mp);            // 30
mp = 99;                         // writes through the pointer
CIO::println(a[2]);              // 99
CIO::println(cause Ref::move(mp));  // refused: pointer moved out of bounds

Recusas como ferramenta de design

As referências recusam o que sua permissão proíbe — e o motivo da recusa é apenas um valor:

CIO::println(cause Ref::write(rr, 99));
// Ref refused: reference is read-only, cannot write

Anotações: @read, @write, @onlyread, @unfork

As anotações declaram contratos sobre fluxos e métodos:

// A stream that must never be forked again:
Stream Sealed {
    void ping();
} @unfork
Sealed BadFork {}       // startup: refused: stream Sealed is @unfork, cannot fork

// A read-only stream: users may not call write methods:
Stream ReadOnly {
    int count;
    void bump();
    int get();
}
ReadOnly RO {
    void bump() { this::count = count + 1; } @write
    int get() { res count; } @read
} @onlyread
  • @write / @read em um método declaram explicitamente sua natureza de leitura/escrita — eles têm prioridade sobre as heurísticas da AST (um corpo que parece somente leitura pode ser declarado como método de escrita, e vice-versa).
  • @onlyread recusa qualquer chamada de método de escrita no fluxo.
  • @unfork recusa qualquer caminho de implementação, incluindo new em uma classe @unfork.

Chamando bibliotecas C nativas

Um fluxo pode se vincular a uma biblioteca compartilhada:

Stream m & "libm.so.6";          // bind libm

Main {
    void exec() {
        CIO::println(get m::sin(0));    // 0
        CIO::println(get m::pow(2, 10)); // 1024
    }
}

Funções binárias são chamadas como double(*)(double, ...) (até 6 argumentos); símbolos exportados tornam-se métodos do fluxo. O bio_dlsym / o shim de plataforma lidam com as diferenças entre dlopen/LoadLibrary, então isso também funciona no Windows.

Gerenciamento de memória

  • O interpretador usa uma arena baseada em blocos — as alocações nunca se movem.
  • Limite padrão: 256 MiB em modo interpretado; 0 = ilimitado.
  • Flags de limite: bio -e 256M script.bio (ou -e 1G, -e 0).
  • Produtos compilados: sem limite, a menos que BIO_MEM_LIMIT esteja definido no ambiente; bio shell build incorpora esse comportamento no main gerado.
  • Quando o limite é atingido, o programa para com uma mensagem clara: memory limit exceeded (limit N bytes).

Desempenho

  • Cache: fluxos e métodos são armazenados em cache no caminho crítico (stream_cache / method_cache) — buscas repetidas pelo mesmo nome são O(1).
  • Compilação incremental: bio build calcula o hash do código-fonte de cada módulo; apenas os módulos alterados são recompilados (N module(s) cached, M recompiled).
  • Modo compilado: bio shell build vincula o runtime do interpretador em um executável autônomo — a inicialização é instantânea e o produto roda em qualquer lugar sem bio.

Compilações multiplataforma

O make bin (via tools/make-dist.sh) compila de forma cruzada as árvores de release para todas as plataformas com zig — sem SDKs externos:

make bin
# bin/linux-x86_64/bin/bio + lib/libbio.so
# bin/win64/bin/bio.exe + lib/bio.dll + bio.bat
# bin/macos-arm64/bin/bio + lib/libbio.dylib
# ...

Plataformas: linux-x86_64, linux-arm64, win32, win64, win-arm64, macos-x86_64, macos-arm64. Requer zig >= 0.14 no PATH.

Detalhes internos: o launcher é vinculado dinamicamente ao runtime compartilhado em lib/ (rpath $ORIGIN/../lib); o Windows usa bio.bat para definir o PATH. As threads usam ucontext no POSIX e fibras Win32 no Windows; bibliotecas binárias usam dlopen ou LoadLibrary através do shim de plataforma.

Mãos à obra: um projeto real

Vamos construir um contador de frequência de palavras que lê um arquivo, conta palavras e imprime um relatório ordenado.

1. Esqueleto

bio init wordcount

2. src/main.bio

program main;

need function countWords;          // provided by utils/counter.bio

Main {
    void exec() {
        if (CIO::getln() == "") { }   // (placeholder for arg reading)
        FIO::open("input.txt");
        string text = FIO::readFile("input.txt");
        ALL report = countWords(text);
        CIO::println(get report);
    }
}

3. utils/counter.bio

program utils;

function countWords(text string) {
    // SIO lets us scan word by word through a string buffer.
    int words = 0;
    for (int i = 0; i < text::length(); i = i + 1;) {
        char c = text[i];
        if (c == ' ' || c == '\n' || c == '\t') {
            words = words + 1;
        }
    }
    res words + 1;    // last word has no trailing space
}

4. Compilar e executar

bio build . -s                 # standalone executable
bio build . -m                 # packaged .img with the platform runtime
bio run .                      # interpret directly

5. Empacotar para distribuição

bio build . -m wordcount.zip   # one distributable file

Esse é o ciclo completo: código-fonte → pacote validado → binário autônomo → pacote multiplataforma.

Depuração

  • bio --tokens file.bio — despeja o fluxo de tokens do lexer.
  • As mensagens de recusa são de primeira classe: cause expr mostra exatamente por que uma requisição falhou.
  • Compile com make PROFILE=sanitize para compilações ASan + UBSan.

Leitura adicional

  • Iniciante — conceitos básicos e fluxo de controle.
  • Intermediário — fluxos, classes, projetos, threads.
  • Packaging — formatos e árvores de release.
  • Exemplos — 15 programas comentados cobrindo todos os recursos (especialmente 11-smart-refs.bio, 14-binary-lib.bio, 15-annotations.bio).

Clone this wiki locally