Native Records
Entscheidung von plan 11 step 31A (2026-10-07). Sie legt den Umfang der
OTP-29-Record-Formen jenseits gewöhnlicher Tupel-Records fest und bestimmt ihre
Darstellung, Operationen und Fehler. Step 31B implementierte die Runtime-Zellen
und CLAUSE_record_v1; 31C kompiliert lokale native Records, 31D qualifizierte
und importierte Formen mit -export_record/-import_record, 31E anonyme
Formen. Tupel-Records stehen unter Terme.
OTP 29 kennzeichnet native Records als experimentell. Die folgenden Fakten
stammen aus den festgelegten maint-29-Quellen (erl_lint,
erl_expand_records, v3_core, beam_core_to_ssa,
erts/emulator/beam/erl_record.c, utils.c, erl_printf_term.c) und aus
Live-Proben mit OTP 29.1.1.
Umfang
Alle drei Formen jenseits der Tupel-Records sind ausgewählt. Sie teilen eine Darstellung, daher brauchen sie keine separate Entscheidung zur Darstellung:
| Form | Syntax | Schritt |
|---|---|---|
| Nativer Record, lokal | -record #r{...}., #r{...}, X#r.f, X#r{...}, Muster, is_record/1,2,3 | 31C |
| Qualifiziert und importiert | #m:r{...}, X#m:r.f, X#m:r{...}, Muster; -export_record, -import_record | 31D |
| Inferiert (anonym) | X#_.f, X#_{...}, Muster #_{...} | 31E |
Nicht ausgewählt: das Reflexionsmodul records (eine Bibliothek, mit der
Bibliotheksarbeit von step 39), term_to_binary (RECORD_EXT) und Hot Code
Upgrade (D01). Aufrufe von records:* bleiben Diagnosen unknown module.
Darstellung
- Deskriptor. Jede Definition eines nativen Records wird zu einem
unveränderlichen
abi::v1::RecordDescriptorneben ihrem Moduldeskriptor kompiliert: der definierendeModuleDescriptor, Atom-Slots für Modul- und Record-Namen, das Export-Flag (-export_recordzur Compile-Zeit) und die Atom-Slots der Feldnamen in Definitionsreihenfolge. Atom-Slots werden über die registrierten Atome des Moduls aufgelöst, wie die Namen inFrameDescriptor. Programme sind statisch (kein Entladen), daher lebt ein Deskriptor so lange wie das Programm; ein anderes Modul des Batches verweist per Symbol auf ihn. Standardwerte werden in jede Konstruktionsstelle kompiliert, nie gespeichert. - Instanz. Heap-Zelle der Art
native_record: Header (Anzahl1 + n), ein nicht verfolgtes Deskriptorwort, dannnverfolgte Werte in Definitionsreihenfolge. Ein Record ohne Felder ist eine Zelle aus zwei Wörtern. - Der Deskriptor hält Modul, Name, Export-Flag und Feldliste bei der Konstruktion fest, wie die erfasste Definition von OTP. Jede Operation nach der Konstruktion liest den Deskriptor der Instanz, nie den Code, der sie ausführt.
- Kopieren, Speicherbereinigung, Durchlauf und Verifikation behandeln die Zelle wie ein Tupel, dessen erstes Nutzdatenwort nicht verfolgt wird. Die Zulassung erfordert einen Deskriptor, der von einem Modul derselben Runtime registriert wurde.
Operationen
M ist das aktuelle Modul. Alle Fehler haben die Klasse error;
badrecord-Nutzlasten sind der fehlerhafte Wert, außer bei fehlgeschlagener
externer Konstruktion.
| Operation | Akzeptiert | Fehlschlag |
|---|---|---|
Lokale Konstruktion #r{...} | Immer (Definition ist lokal) | Unbekanntes Feld oder fehlender Wert sind Kompilierfehler |
Externe Konstruktion #m:r{...} (auch importiertes #r{...}, auch #M:r) | m:r im Batch definiert und exportiert | {badrecord, {m, r}}; dann {badfield, {{m, r}, F}}, {novalue, {{m, r}, F}} (badfield gewinnt) |
Lokaler Zugriff X#r.f | Nativer Record namens r (Modul und Export-Flag werden nicht geprüft, wie in der Runtime von OTP) | {badrecord, X}; fehlendes Feld {badfield, {{Mod, r}, f}} |
Externer Zugriff X#m:r.f | Modul m, Name r, exportiert | {badrecord, X}; {badfield, ...} |
Anonymer Zugriff X#_.f | Jeder native Record (Export wird nicht geprüft, wie in der Runtime von OTP) | {badrecord, X}; {badfield, ...} |
Lokale Aktualisierung X#r{...} | Modul M, Name r | {badrecord, X}; unbekanntes Feld {badfield, ...} |
Externe Aktualisierung X#m:r{...} | Exportiert, Modul m, Name r | ebenso |
Anonyme Aktualisierung X#_{...} | Exportiert oder Modul M | ebenso |
Lokales Muster #r{...} | Modul M, Name r, jedes aufgeführte Feld vorhanden | kein Match |
Externes Muster #m:r{...} | Modul m, Name r; exportiert, wenn ein Feld aufgeführt ist | kein Match |
Anonymes Muster #_{...} | Jeder native Record; exportiert oder Modul M, wenn ein Feld aufgeführt ist | kein Match |
- Die Konstruktion wertet die angegebenen Felder in Quelltextreihenfolge aus (Standardwerte sind Literale); eine Aktualisierung wertet zuerst den Record aus, dann die neuen Werte in Quelltextreihenfolge, anders als eine Aktualisierung eines Tupel-Records. Leere Aktualisierungen prüfen trotzdem.
- Guards: nur Feldzugriff (ein Fehlschlag lässt den Guard fehlschlagen) und
is_record. Konstruktion in einem Guard ergibtcreating a record in a guard is only supported for tuple records; Aktualisierung ergibtillegal guard expression. is_record(X)ist nur für native Records wahr.is_record(X, r)mit einem lokalen nativenrprüft ModulMund Namer; mit einem ausmimportiertenrprüft es Modulm.is_record(X, m, r)mit Atomen prüft Modul und Name; mit einer Ganzzahl ist es der Tupeltest.- Native Records sind keine Tupel:
is_tupleist false; Element- und Größendienste weisen sie ab.
Regeln zur Compile-Zeit
Die Meldungen folgen erl_lint:
- Standardwerte müssen nach der Konstantenfaltung literal sein (Zahlen, Atome,
Zeichenketten,
[], Conses/Tupel/Maps daraus, Binaries nur aus Zeichenketten):illegal default value for field a in native record r. - Lokale Konstruktion ohne Wert für ein Feld ohne Standardwert:
field a is not initialized in native record r; unbekanntes Feld:field zz undefined in record r. Unbekannte Felder in Zugriff, Aktualisierung und Mustern werden akzeptiert (OTP warnt nur); sie schlagen zur Laufzeit fehl. - Index
#r.a,record_info/2, Initialisierer_ = Vund typisierte Feldverfeinerungen gibt es nur für Tupel-Records, mit den Meldungen von OTP. - Ein Name ist entweder ein Tupel-Record, ein nativer Record oder ein
importierter Record; Konflikte und fehlerhafte Formen von
-export_record/-import_recordsind Fehler.-export_recordmuss vor den Funktionsdefinitionen stehen. - Externe Formen, die ein Modul außerhalb des Batches, einen undefinierten oder
einen nicht exportierten Record benennen, kompilieren und schlagen wie in OTP
zur Laufzeit fehl. Externe Konstruktion wird zur Compile-Zeit gegen den Batch
aufgelöst: Das importierende Modul führt das Lowering der literalen
Standardwerte des definierenden Moduls selbst durch und referenziert dessen
exportierten
Deskriptor; unbekannte Felder lösen
badfieldaus, bevor ein fehlender Wertnovalueauslöst (ErrorReason21).
Ausgabe und Ordnung
erlang:display/1gibt#m:r{a=1,b=2}aus: keine Leerzeichen, Felder in Definitionsreihenfolge. OTP gibt Felder in der Reihenfolge der Atomtabellen-Indizes aus, die von der Erzeugungsreihenfolge der Atome abhängt und nicht reproduzierbar ist; dies ist ein festgehaltener Unterschied, wie bei Map-Schlüsseln.- Term-Ordnung: Tupel < nativer Record < Map. Records werden nach Modul, Name,
Export-Flag (false zuerst), Feldanzahl, Feldnamen in Definitionsreihenfolge
und dann Werten in Definitionsreihenfolge verglichen.
=:=verlangt zusätzlich dieselbe Feldreihenfolge;==vergleicht Werte numerisch (der Compiler von OTP faltet manche==auf Records zu=:=; befolgt wird die Runtime-Regel).
Beibehaltene Unterschiede
| OTP | Clause |
|---|---|
Feldreihenfolge von display folgt Atom-Indizes | Definitionsreihenfolge |
| Externe Konstruktion eines nicht geladenen Moduls schlägt fehl, bis es geladen ist | Jedes Modul des Batches wird beim Start geladen; ein Modul außerhalb des Batches schlägt immer fehl |
Der Compiler kann == zwischen Records zu =:= falten (#r{a=1} == #r{a=1.0} ist false) | Runtime-== (true) |
| Unbekannte Felder in Zugriff/Aktualisierung/Mustern, qualifizierte Konstruktion im eigenen Modul ohne Werte, ungenutzte oder in Headern definierte Records: Warnungen | Keine Warnungen |
Clause