Подання термів
Допущені види: атоми/булеві значення, довільні цілі числа, скінченні числа з рухомою комою binary64, кортежі, правильні/неправильні списки та рядки, map, bitstring і звичайні кортежні record; native records (native records); fun (функціональні значення); локальні pid, порти та посилання (нижче, порти). Кодування слів описано в abi.md.
Володіння
- Складені значення живуть у купі свого процесу (runtime). Вказівники процесу завжди вказують на початок об'єкта. Допуск перевіряє володіння: слово вказує, з вирівнюванням за словом, нижче за вершину блоку купи процесу або одного з його фрагментів, і заголовок (або cons-комірка) за цією адресою відповідає його тегу (допуск). Чужі та застарілі слова відхиляються без жодного читання пам'яті. Вид і розмір декодуються із заголовка.
Termхоста для значення в купі — це сире слово з тегом, дійсне до наступного збирання сміття в його купі (корені); воно не закріплює пам'ять купи. Після знищення контексту доступ повертаєexpired_context; після пізнішого збирання —stale_term. Терми завжди можна безпечно знищувати.- Конструювання перевіряє дочірні значення, резервує пам'ять, ініціалізує, а потім публікує за один крок; у разі невдачі пам'ять і лічильники відкочуються.
Term::from_word(word)допускає лише безпосередні значення, що не залежать від власника;Term::from_word(word, context)також допускає атоми та терми купи цього контексту. Передавання в межах тієї самої купи зберігає ідентичність.copy_to/ProcessHeap::addкопіюють граф іншого процесу того самого runtime зі збереженням спільних частин; фабрики термів відхиляють чужі вхідні дані зwrong_owner(копіювання між купами).- Комірки живуть, доки явне збирання сміття не виявить їх недосяжними, або до знищення купи.
Атоми
AtomStorageна кожен runtime, ліниве інтернування за точним написанням UTF-8, без нормалізації та витіснення.RuntimeOptions::max_atoms1..2^26, за замовчуванням 2^20; назви модулів/експортів враховуються. Уже наявні написання успішно обробляються і при заповненій таблиці.- До 255 скалярних значень Unicode; порожні, NUL і додаткові символи дозволено; пошкоджений/надмірно довгий/сурогатний UTF-8 відхиляється.
- Корисне навантаження береться з лічильника на весь процес ОС, тож слово атома чужого runtime можна виявити. 32-бітні процеси мають загалом 2^26 ідентичностей за весь час роботи.
- Атомні
Termхоста закріплюють написання і переживають знищення runtime. Перенесення атома між runtime означає інтернуванняatom_utf8()у цільовому. - Булеві значення — це атоми
true/false. - Інтернування і пошук безпечні для одночасних робочих потоків планувальника (потоки); написання зберігає одне слово.
Цілі числа
- Значення, що вміщуються в 28/60-бітне корисне навантаження цілі, є безпосередніми; більші — незмінні комірки зі знаком і модулем. Нуль і малі значення завжди нормалізуються до безпосередніх. Звуження літералів до ширини хоста немає.
- Згенеровані
+,-,*пробують вбудований швидкий шлях для двох безпосередніх значень (обчислення подвійної ширини з явними межами), інакше викликають сервіс runtime. divвідкидає дробову частину в бік нуля;remбере знак діленого; побітові операції використовують нескінченний додатковий код; від'ємна кількість зсуву змінює напрямок; величезні зсуви праворуч насичуються до 0 або -1.- Помилки: неправильні операнди і нульовий дільник →
badarith;abs/1→badarg. - Обмеження: як в ERTS, модуль займає щонайбільше
BIG_ARITY_MAXслів: 4 194 240 біт на 64-бітних цілях (65 535 слів), 4 194 272 на 32-бітних (131 071 слово); десятковий текст відповідно (1 262 593 і 1 262 602 цифри). Більший арифметичний результат викликаєerror:system_limitу тілі (ValueOutcome::system_limit, ABI) і робить guard невдалим; цілочисловий сегмент, що вилучає більше значення, не збігається. Компілятор відхиляє літерал понад 4 194 240 біт (illegal integer, як сканер OTP) і константний зразок понад цю межу (illegal pattern).
Числа з рухомою комою
- Біти IEEE binary64 передаються в runtime як вісім байтів у мережевому порядку; NaN і нескінченність відхиляються. Без fast-math.
+ - *лишаються точними для двох цілих чисел; будь-який операнд із рухомою комою спричиняє використання binary64./завжди перетворює обидва. Нескінченні результати та нульові дільники →badarith.float/1округлює до найближчого парного;round/1при рівновіддаленості округлює від нуля;trunc,floor,ceilповертають довільні цілі числа. Неправильні операнди →badarg.- Точна рівність розрізняє
1і1.0, а також0.0і-0.0; числове порівняння порівнює точну цілу частину і дріб числа з рухомою комою, ніколи не округлюючи ціле число.min/maxпри рівності повертають перший операнд.
Кортежі, списки, рядки
- Кортеж: заголовок з арністю + поля. Cons: слова голови + хвоста.
{}і[]є безпосередніми значеннями. Рядки — це списки кодових точок. Списки не мають обмеження довжини, крім пам'яті (зокрема необов'язкового бюджету купи). Кортежі містять до 16 777 215 елементів (MAX_TUPLE_ARITY,MAX_ARITYVALв OTP); конструктори повідомляють про більший якresource_limit, вбудовані функції викликатимутьbadarg. - Сервіси:
hd,tl,length,tuple_size,size,elementз нумерацією від одиниці.
Map
- Незмінні таблиці, відсортовані за точним порядком ключів. Дублікати ключів
під час конструювання зберігають останнє значення. Конструювання сортує
ключі (O(n log n) порівнянь; уже впорядковані за зростанням ключі лише
перевіряються); оновлення вставляють за допомогою двійкового пошуку. Немає
обмеження розміру чи роботи, крім пам'яті, як в OTP; на 32-бітних цілях
кількість слів у заголовку обмежує map 2^24 - 1 записами (
resource_limit). Цілочислові ключі та ключі з рухомою комою різняться (також0.0і-0.0, також у вкладених значеннях). - Оновлення
K := Vвимагають наявності ключа;K => Vвставляє або замінює. Оновлення готують нову таблицю і публікують її один раз. - Помилки в тілі:
{badmap, M},{badkey, K}; guard натомість відхиляють. - Сервіси:
is_map,map_size,map_get,is_map_key, конструювання, оновлення.
Bitstring
- Упаковані від старшого біта, з точною довжиною в бітах і обнуленим доповненням. До 64 байтів зберігаються безпосередньо в binary купи, розмір якого відповідає даним; більші значення використовують спільний незмінний буфер поза купою, на який дивляться позакупні комірки binary, спільні з вилученими хвостами. Буфер враховується один раз для процесу, що його створив. Обмеження розміру немає, крім необов'язкового бюджету купи процесу; цілочислові сегменти записуються без побудови цілого числа такої ж ширини, як сегмент.
- Конструювання готує всі сегменти перед публікацією. Цілочислові сегменти обрізаються; нативний порядок байтів береться з розміщення даних цілі.
- Сегменти з рухомою комою: ширина 16/32/64; конструювання може кодувати
нескінченність, але зіставлення відхиляє нескінченні поля та поля NaN.
Зіставлення з рухомою комою нульової ширини вилучає
0.0. - Сегменти UTF-8/16/32 перевіряють скалярні значення, сурогати і обрізання.
- Зіставлення просуває явний бітовий курсор лише в разі успіху;
:allяк явний розмір недійсний. - Сервіси:
is_binary,is_bitstring,bit_size,byte_size(округлює вгору),size(округлює вниз),binary_part/2,3. Помилки →badarg.
Record
- Звичайні record розгортаються в кортежі
{Tag, Fields...}. Оголошення мають передувати використанню; дублікати, невідомі поля, посилання вперед/на себе і недійсні поля з підстановочним знаком є помилками. - Конструювання обчислює поля в порядку оголошення: явне значення, інакше
значення за замовчуванням
_ = V, інакше оголошене значення за замовчуванням, інакшеundefined. Кожне значення за замовчуванням обчислюється окремо для кожного використання. - Зразки перевіряють арність і тег, потім лише перелічені поля.
#r.f— індекс з нумерацією від одиниці (тег на позиції 1). - Доступ до поля перевіряє арність і тег; невдача дає
{badrecord, V}у тілах і відхилення в guard. is_record(V, r)використовує оголошену арність.is_record/3потребує атомного тегу і цілої арності (недодатна → false; неправильні типи →badarg); атом як третій аргумент — це запит щодо native record, і він повертає false. Guard вимагають буквальних аргументів.- Оновлення
Expr#r{f = V, ...}обчислює нові значення в порядку вихідного коду, потімExpr, потім перевіряє арність і тег ({badrecord, Value}у разі невідповідності, також дляExpr#r{}) і будує новий кортеж; інші поля копіюються._ = Vв оновленнях відхиляється; оновлення недопустимі в зразках і guard. record_info(fields | size, r)розгортається під час компіляції в список назв полів або розмір кортежу. Обидва аргументи мають бути буквальними атомами, аr— раніше оголошеним кортежним record; у guard це недопустимо, а локальнаrecord_info/2відхиляється як уже визначена.- Native records: native records (локальні, кваліфіковані, імпортовані та анонімні форми).
Pid і посилання
План 11, step 42. self/0 повертає pid процесу, що викликає, make_ref/0 —
нове посилання; pid_to_list/1 і ref_to_list/1 повертають їхній текст.
- Pid — безпосереднє слово (молодші чотири біти
0x3), що містить номер процесу. Номери беруться з однієї послідовності на весь процес ОС і ніколи не використовуються повторно, тож runtime допускає слово pid лише тоді, коли сам видав цей номер: підроблене слово (ніколи не видане) або pid іншого runtime даєwrong_owner. Pid завершеного процесу лишається дійсним термом, як в OTP. 32-бітні цілі мають 2^28 номерів на один запуск програми, 64-бітні — 2^60; створення процесу понад цю межу завершується зresource_limit. - Порт (step 57B плану) — безпосереднє слово (молодші чотири біти
0x7), що містить його номер із власної послідовності без повторного використання, допускається як pid; друкується як#Port<0.N>і впорядковується між fun і pid (порти). - Посилання — комірка купи (
reference: заголовок плюс невідстежуване 64-бітне число), що допускається, як і кожен терм купи: лише у власному процесі, застаріває після збирання сміття дляTermхоста, копіюється між процесами за значенням. Номери беруться з одного лічильника на весь процес ОС, тож кожне посилання в межах запуску програми унікальне. - Друк дотримується локальних ідентичностей OTP: pid як
<0.N.S>(N — молодші 28 бітів його номера, S — решта), посилання як#Ref<0.A.B.C>(C — молодші 18 бітів його номера, B — наступні 32, A — решта), в обох стилях~wі display. Pid упорядковуються за номером, посилання — за номером, тож пізніші посилання програми впорядковуються після раніших.
Порівняння і порядок
Ітеративне, без обмеження роботи, як в OTP: порівняння обмежує лише пам'ять для пар в очікуванні, зокрема пошуки ключів map, а ідентичні слова рівні без обходу. Bitstring, вирівняні за байтами, порівнюються цілими байтами одразу. Порядок: числа < атоми < посилання < fun < pid < кортежі < native records < map < nil < списки < bitstring (fun упорядковуються між собою). Атоми порівнюються за написанням UTF-8 (порядок кодових точок); кортежі — за арністю, потім за полями; map — за розміром, потім ключами, потім значеннями; bitstring — за логічними бітами.
Друк
format_term (output.hpp)
відображає будь-який допущений терм в одному з двох стилів OTP. Цілі числа,
кортежі (record є кортежами) і вкладеність виглядають однаково в обох.
~w (TermStyle::write) | erlang:display/1 (TermStyle::display) | |
|---|---|---|
| Атоми | У лапках, якщо не починаються з малої літери Latin-1, за якою йдуть символи імені (з @); зарезервовані слова і maybe/else беруться в лапки; символи поза Latin-1 екрануються як \x{H} | У лапках, якщо не починаються з малої літери Latin-1, за якою йдуть літери, цифри або _; для зарезервованих слів і @ особливого правила немає; UTF-8 зберігається |
| Числа з рухомою комою | Найкоротше подання для точного відновлення в розміщенні OTP: 0.1, 100.0, 1.0e16, 1.5e-7 | C %.6e: 1.500000e+00 |
| Списки | Елементи: [104,105], [1,2|3] | Плаский список друкованих байтів Latin-1 друкується як "hi" (сирі байти; екрануються лише \n і ") |
| Bitstring | <<1,2,5:3>> | Друкований ASCII binary друкується як <<"hi">>, інші — як ~w |
| Map | #{k => v,k2 => v2} | #{k=>v,k2=>v2} |
- Map друкуються в порядку ключів map (
maps:iterator(M, ordered), як~kwв OTP). Типовий~wіerlang:display/1в OTP натомість дотримуються внутрішнього розміщення: порядку таблиці атомів для атомних ключів малих map (він різниться між запусками VM) і порядку хешів понад 32 ключі. Clause цей порядок не відтворює. - Відображення ітеративне, тож глибину обмежує лише сам терм. Текст за
замовчуванням обмежено 64 MiB; перевищення (наприклад, через широко спільний
підтерм) завершується з
resource_limitі не повертає часткового тексту. - Еталони:
runtime_printingпорівнює обидва стилі з OTP для 9 542 значень (усі результати корпусу плюс авторські граничні випадки); рядки display, порядок map яких в OTP є внутрішнім, пропускаються (фікстури).
Clause