Skip to content

Advanced es

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

Avanzado — Referencias inteligentes, bibliotecas, memoria y proyectos reales

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

Clase magistral: referencias inteligentes tipadas, llamadas a bibliotecas C nativas, gestión de memoria, rendimiento, anotaciones como herramientas de diseño y un proyecto práctico completo.

Referencias inteligentes tipadas

Una referencia inteligente es un valor tipado que apunta a un lvalue. Se declara con permiso × nivel × tipo base:

&<permission> <follow> <base type> <name> = &<lvalue>;
  • Permisos (7 pilas): r lectura, w escritura, m mover (puntero), rw, rm, wm, rwm.
  • Niveles (4): u nivel de programa (Unistream), f nivel de método, a nivel de ámbito/área, t nivel de hilo.
  • Tipo base: int / double / float / string / char / arrays / clases — genérico.

Es decir, 7 × 4 = 28 tipos de referencia.

Leer, escribir, mover

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

Movimiento del puntero (permiso m)

Con m, la referencia es un puntero móvil (como a++ en 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

Los rechazos como herramienta de diseño

Las referencias rechazan lo que su permiso prohíbe — y el motivo del rechazo es solo un valor:

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

Anotaciones: @read, @write, @onlyread, @unfork

Las anotaciones declaran contratos sobre flujos y 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 en un método declaran explícitamente su naturaleza de lectura/escritura — tienen prioridad sobre las heurísticas del AST (un cuerpo que parece de solo lectura puede declararse como método de escritura, y viceversa).
  • @onlyread rechaza cualquier llamada a métodos de escritura en el flujo.
  • @unfork rechaza toda vía de bifurcación, incluida new sobre una clase @unfork.

Llamar a bibliotecas C nativas

Un flujo puede enlazarse a una biblioteca compartida:

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
    }
}

Las funciones binarias se llaman como double(*)(double, ...) (hasta 6 argumentos); los símbolos exportados se convierten en métodos del flujo. bio_dlsym / la capa de compatibilidad de la plataforma gestiona las diferencias entre dlopen y LoadLibrary, de modo que esto también funciona en Windows.

Gestión de memoria

  • El intérprete usa una arena basada en bloques — las asignaciones nunca se mueven.
  • Límite predeterminado: 256 MiB en modo interpretado; 0 = ilimitado.
  • Banderas de límite: bio -e 256M script.bio (o -e 1G, -e 0).
  • Productos compilados: sin límite salvo que BIO_MEM_LIMIT esté definido en el entorno; bio shell build incrusta este comportamiento en el main generado.
  • Cuando se alcanza el límite, el programa se detiene con un mensaje claro: memory limit exceeded (limit N bytes).

Rendimiento

  • Caché: los flujos y métodos se almacenan en caché en la ruta de acceso frecuente (stream_cache / method_cache) — las búsquedas repetidas por el mismo nombre son O(1).
  • Compilación incremental: bio build calcula el hash del código fuente de cada módulo; solo se recompilan los módulos modificados (N module(s) cached, M recompiled).
  • Modo compilación: bio shell build enlaza el runtime del intérprete en un ejecutable autónomo — el arranque es instantáneo y el producto se ejecuta en cualquier lugar sin bio.

Compilaciones multiplataforma

make bin (mediante tools/make-dist.sh) compila de forma cruzada árboles de distribución para todas las plataformas con zig — sin SDK 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. Requiere zig >= 0.14 en PATH.

Detalles internos: el lanzador está enlazado dinámicamente contra el runtime compartido en lib/ (rpath $ORIGIN/../lib); Windows usa bio.bat para configurar PATH. Los hilos usan ucontext en POSIX y fibras Win32 en Windows; las bibliotecas binarias usan dlopen o LoadLibrary a través de la capa de compatibilidad de la plataforma.

Práctica: un proyecto real

Vamos a construir un contador de frecuencia de palabras que lee un archivo, cuenta las palabras e imprime un informe 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 y ejecutar

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

5. Empaquetar para distribución

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

Ese es el ciclo completo: código fuente → paquete validado → binario autónomo → paquete multiplataforma.

Depuración

  • bio --tokens file.bio — vuelca el flujo de tokens del analizador léxico.
  • Los mensajes de rechazo son de primera clase: cause expr muestra exactamente por qué falló una solicitud.
  • Compila con make PROFILE=sanitize para obtener compilaciones ASan + UBSan.

Lecturas adicionales

  • Principiante — conceptos básicos y flujo de control.
  • Intermedio — flujos, clases, proyectos, hilos.
  • Packaging — formatos y árboles de distribución.
  • Ejemplos — 15 programas comentados que cubren todas las características (en especial 11-smart-refs.bio, 14-binary-lib.bio, 15-annotations.bio).

Clone this wiki locally