Skip to content

Advanced de

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

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

Experte — Intelligente Referenzen, Bibliotheken, Speicher und echte Projekte

Meisterkurs: typisierte intelligente Referenzen, Aufruf nativer C-Bibliotheken, Speicherverwaltung, Performance, Annotationen als Designwerkzeuge und ein vollständiges Praxisprojekt.

Typisierte intelligente Referenzen

Eine intelligente Referenz ist ein typisierter Wert, der auf einen Lvalue zeigt. Sie wird deklariert mit Berechtigung × Ebene × Basistyp:

&<permission> <follow> <base type> <name> = &<lvalue>;
  • Berechtigungen (7 Stapel): r lesen, w schreiben, m bewegen (Zeiger), rw, rm, wm, rwm.
  • Ebenen (4): u Programmebene (Unistream), f Methodenebene, a Scope-/Bereichsebene, t Threadebene.
  • Basistyp: int / double / float / string / char / Arrays / Klassen — generisch.

Das ergibt 7 × 4 = 28 Referenztypen.

Lesen, Schreiben, Bewegen

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

Zeigerbewegung (m-Berechtigung)

Mit m ist die Referenz ein beweglicher Zeiger (wie a++ in 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

Ablehnungen als Designwerkzeug

Referenzen lehnen ab, was ihre Berechtigung verbietet — und der Ablehnungsgrund ist einfach ein Wert:

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

Annotationen: @read, @write, @onlyread, @unfork

Annotationen deklarieren Verträge auf Streams und Methoden:

// 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 an einer Methode deklarieren ihre Lese-/Schreibnatur explizit — sie haben Vorrang vor AST-Heuristiken (ein Rumpf, der wie reine Lektüre aussieht, kann als Schreibmethode deklariert werden, und umgekehrt).
  • @onlyread lehnt jeden Aufruf einer Schreibmethode auf dem Stream ab.
  • @unfork lehnt jeden Implementierungspfad ab, einschließlich new auf einer @unfork-Klasse.

Native C-Bibliotheken aufrufen

Ein Stream kann an eine gemeinsam genutzte Bibliothek binden:

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

Binärfunktionen werden als double(*)(double, ...) aufgerufen (bis zu 6 Argumente); exportierte Symbole werden zu Stream-Methoden. bio_dlsym / der Plattform-Shim behandelt die Unterschiede zwischen dlopen und LoadLibrary, sodass das auch unter Windows funktioniert.

Speicherverwaltung

  • Der Interpreter verwendet eine blockbasierte Arena — Zuweisungen bewegen sich nie.
  • Standardlimit: 256 MiB im interpretierten Modus; 0 = unbegrenzt.
  • Limit-Flags: bio -e 256M script.bio (oder -e 1G, -e 0).
  • Kompilierte Produkte: kein Limit, sofern nicht BIO_MEM_LIMIT in der Umgebung gesetzt ist; bio shell build bettet dieses Verhalten in den erzeugten main ein.
  • Wird das Limit erreicht, stoppt das Programm mit einer klaren Meldung: memory limit exceeded (limit N bytes).

Performance

  • Caching: Streams und Methoden werden auf dem heißen Pfad gecacht (stream_cache / method_cache) — wiederholte Lookups nach demselben Namen sind O(1).
  • Inkrementelle Kompilierung: bio build hasht den Quellcode jedes Moduls; nur geänderte Module werden neu kompiliert (N module(s) cached, M recompiled).
  • Kompiliermodus: bio shell build linkt die Interpreter-Laufzeit in eine eigenständige ausführbare Datei — der Start ist sofortig und das Produkt läuft überall ohne bio.

Plattformübergreifende Builds

make bin (über tools/make-dist.sh) erzeugt mit zig Release-Bäume für alle Plattformen — keine fremden SDKs:

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
# ...

Plattformen: linux-x86_64, linux-arm64, win32, win64, win-arm64, macos-x86_64, macos-arm64. Erfordert zig >= 0.14 im PATH.

Interna: Der Launcher ist dynamisch gegen die gemeinsame Laufzeit in lib/ gelinkt (rpath $ORIGIN/../lib); Windows verwendet bio.bat, um PATH zu setzen. Threads nutzen ucontext unter POSIX und Win32-Fibers unter Windows; Binärbibliotheken verwenden dlopen oder LoadLibrary über den Plattform-Shim.

Praxisteil: ein echtes Projekt

Lass uns einen Wortfrequenzzähler bauen, der eine Datei liest, Wörter zählt und einen sortierten Bericht ausgibt.

1. Gerüst

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. Erstellen und ausführen

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

5. Für die Verteilung paketieren

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

Das ist der komplette Kreislauf: Quelle → validiertes Bündel → eigenständiges Binary → plattformübergreifendes Paket.

Debugging

  • bio --tokens file.bio — den Token-Strom des Lexers ausgeben.
  • Ablehnungsmeldungen sind erstklassig: cause expr zeigt genau, warum eine Anfrage fehlgeschlagen ist.
  • Kompiliere mit make PROFILE=sanitize für ASan- + UBSan-Builds.

Weiterführendes

  • Einsteiger — Grundlagen und Kontrollfluss.
  • Fortgeschrittene — Streams, Klassen, Projekte, Threads.
  • Packaging — Formate und Release-Bäume.
  • Beispiele — 15 kommentierte Programme, die jedes Feature abdecken (insbesondere 11-smart-refs.bio, 14-binary-lib.bio, 15-annotations.bio).

Clone this wiki locally