Відмінності від Erlang/OTP
Поведінка, що спостерігається, у якій Clause свідомо відрізняється від
зафіксованого OTP 29 (maint-29, див. otp-reference.md).
Кожен запис посилається на контракт, якому він належить. Запис видаляють, щойно
відмінність усунуто. Ще не реалізовані можливості (про які повідомляється як
notimpl) тут не наведено; див. features.md і план.
Map
| Відмінність | OTP | Clause | Власник |
|---|---|---|---|
Порядок генератора map (K := V <- M) | Пласкі map (до 32 ключів) перебираються в порядку ключів, але атомні ключі — в порядку таблиці атомів, який різниться між запусками VM; більші map — у порядку хешів | Завжди канонічний порядок ключів (порядок термів) | зразки |
Вміст bad_generators для генератора map у zip-групі | Його ітератор: ланцюжок {K, V, Next}, що закінчується none, у порядку OTP | Той самий ланцюжок, побудований у канонічному порядку ключів | зразки |
Друк map (erlang:display/1, ~w, ~p) | Порядок внутрішнього розміщення (порядок таблиці атомів для атомних ключів, порядок хешів понад 32 ключі) | Порядок ключів map, як ~kw в OTP | терми |
Друк native record (erlang:display/1) | Поля в порядку індексів таблиці атомів | Порядок визначення, як ~w | native records |
== між native record, поля яких відрізняються лише як ціле число/число з рухомою комою | Компілятор може згорнути його до =:= (false) | Числове порівняння (true) | native records |
Друк локального fun (#Fun<M.Index.Uniq>) | Індекс із нумерації лямбд компілятора, Uniq — хеш коду модуля | Індекс серед локальних fun модуля в порядку вихідного коду, Uniq завжди 0 | fun |
| Порядок двох локальних fun одного модуля | За індексом OTP | За індексом у порядку вихідного коду, тож fun різних функцій можуть упорядковуватися інакше | fun |
Імена анонімних fun у трасуваннях стека (-f/1-fun-N-) | N з нумерації компілятора | N лічить fun функції f/1 у порядку вихідного коду | fun |
| Анонімний fun у значенні за замовчуванням поля record | Кожне місце конструювання розгортає власну копію: fun із двох місць нерівні | Один fun для значення за замовчуванням: fun з будь-якого місця конструювання рівні | fun |
| Порядок захоплених значень fun, створених усередині comprehension | Вільні змінні згенерованої функції comprehension | Порядок визначення в охопній функції; помітно лише при порівнянні двох таких fun | fun |
Pid, посилання і процеси
| Відмінність | OTP | Clause | Власник |
|---|---|---|---|
| Номери pid | Перший процес користувача — приблизно <0.80.0>; номери повторно використовуються після переповнення таблиці pid | Перший процес — <0.1.0>; номери беруться з однієї послідовності й ніколи не використовуються повторно | терми |
Код після spawn(Fun) для fun іншої арності | Аналіз типів компілятора може вважати код після виклику недосяжним і відкинути його, тож викликач одразу повертає pid | Викликач продовжує роботу; завершується з помилкою лише новий процес, з {badarity, {Fun, []}} | процеси |
Форматування великого терма (io:format/1,2) | Виконується в коді Erlang (io_lib) і в group leader, тож процес може бути витіснений під час форматування | Виконується до кінця в одному виклику вбудованої функції; інші процеси чекають | вбудовані функції |
Прапорці process_flag/2 | trap_exit, priority, message_queue_data, min_heap_size та інші | Лише trap_exit; будь-який інший прапорець викликає badarg | процеси |
| Порядок звітів про помилки процесів, що аварійно завершуються одночасно | Порядок logger | Порядок, у якому їх завершують їхні робочі потоки | процеси |
| Сигнали процесу, що виконується на іншому планувальнику | Ставляться в чергу сигналів і обробляються пізніше, поки відправник продовжує роботу | Відправник чекає, доки закінчиться квант часу цілі, і тоді діє одразу; помітно лише за часом | процеси |
list_to_port/1 для номера, який ніколи не видавався | Повертає терм порту | badarg: допускаються лише порти, відкриті цією програмою | порти |
Значення port_info/1,2 | id — індекс таблиці; memory, queue_size, locking описують драйвер | id — номер порту; memory і queue_size дорівнюють 0; locking — port_level | порти |
| Запис у файл, відкритий лише для читання | {error, eacces} у Windows, {error, ebadf} деінде | {error, ebadf} скрізь | порти |
io:get_line, io:get_chars і file:read/2 у режимі списку на не-ASCII введенні | Символи декодуються відповідно до кодування пристрою | Один елемент списку на байт | порти |
Результат os:cmd/1 | Символи Unicode, декодовані з виводу | Байти виводу | порти |
Порожні аргументи {spawn_executable, F} у Windows | Відкидаються з командного рядка | Передаються як "" | порти |
{exit_status, S} і eof запущеної програми | Порядок не визначено, exit_status може надійти раніше за останні дані | Після всіх даних, перед eof | порти |
| Зайняті порти | Порт із надто великою чергою виводу призупиняє відправників; force у port_command/3 працює з драйверами, які це дозволяють | Вивід ніколи не призупиняє; force викликає notsup на кожному драйвері | порти |
{active, N} для сокетів | Ціле N лічить повідомлення до {tcp_passive, S} | exit(badarg); лише true, false і once | порти |
Параметри налаштування сокетів (nodelay, keepalive, send_timeout, delay_send, буфери) | Застосовуються; інші параметри inet (header, {packet, line}, http, ...) працюють | Перелічені параметри налаштування приймаються, але не застосовуються; інші параметри — exit(badarg) | порти |
| Причини помилок сокетів | Кожна причина POSIX, про яку повідомляє система | Поширені (econnrefused, eaddrinuse, econnreset, etimedout, ...); інші — eio | порти |
| Введення порту, коли під'єднаний процес утримує 1 024 повідомлення і може виконуватися | Продовжує читати й доставляти | Припиняє доставку, доки не закінчиться квант часу процесу; понад 64 KiB утримуваних даних припиняє читання, тож програма, що пише, блокується | порти |
gen_tcp:close/1 із виводом у черзі | Чекає до межі linger/send_timeout, поки вивід буде відправлено | Повертається одразу; потік вводу-виводу надсилає вивід із черги, потім закриває | порти |
Типи monitor/2 | process, port, time_offset | process і port; time_offset викликає badarg (зміщення часу не змінюється) | процеси |
exit/2, exit_signal/2 до посилання | Надсилає псевдоніму процесу, якщо посилання активне | Нічого (псевдонімів немає) | процеси |
| Номери посилань | Поєднують ідентифікатор планувальника і лічильники окремих планувальників (#Ref<0.178111994.4235460610.214105>) | Один лічильник на всю програму (#Ref<0.0.0.1>), тож посилання впорядковані за часом створення | терми |
Помилки, трасування стека і звіти
| Відмінність | OTP | Clause | Власник |
|---|---|---|---|
| Розташування в трасуванні стека | [{file, F}, {line, L}], error_info для error/3 | Завжди []; без error_info | ABI |
Верхній фрейм function_clause | Список аргументів | Арність | ABI |
Верхній фрейм undef | {M, F, Args, []} відсутньої функції | Фрейм функції, що викликає | fun |
| Фрейми BIF/операторів, що завершилися з помилкою | Присутні ({erlang, '+', Args, ...}) | Відсутні; нічого нижче за вхідну функцію | ABI |
Таблиця атомів заповнена (list_to_atom/1) | Емулятор аварійно зупиняється (no more index entries in atom_tab) і записує crash dump | clau: runtime failure: entry call failed: resource_limit, код виходу 70 | вбудовані функції |
list_to_integer/1,2 із символами понад 255 | Його перші цифри використовують лише молодший байт кожного символу ([16#131] дає 1) | badarg | вбудовані функції |
erlang:function_exported/3 для BIF | True для кожного BIF емулятора | True лише для вбудованих функцій, які надає цей runtime | вбудовані функції |
| Звіти про помилки аварійно завершених процесів | Надсилаються до logger, записуються пізніше його обробником за замовчуванням (у стандартний вивід під erl, часто губляться, коли escript зупиняється раніше) | Записуються в stderr, коли процес завершується, до будь-якого подальшого виводу | процеси |
| Виклики функцій, що ніколи не повертаються | Компілюються як хвостові виклики (викликача немає в трасуванні) | Звичайні виклики (викликач присутній) | ABI |
| Пам'ять хоста вичерпано | Емулятор повідомляє, що не може виділити пам'ять, записує crash dump і зупиняється | clau: runtime failure: entry call failed: out_of_memory, код виходу 70, без dump | купа runtime |
| Обмеження пам'яті процесу | max_heap_size (у словах, купа і стек) вбиває процес із причиною killed і журналює звіт про помилку | --max-heap / --max-stack (у байтах) і загальний для runtime --max-memory завершують процес, що запитує пам'ять, як resource_limit: clau: runtime failure: entry call failed: resource_limit, код виходу 70 | купа runtime |
| Аргументи програми | escript передає кожен аргумент у main/1; прапорці емулятора (+t) беруться з %%! або ERL_FLAGS | Початкові параметри runtime (--max-atoms, --max-heap, --max-stack, --max-memory, --args-file, --) вилучаються першими; CLAUSE_FLAGS містить ті самі параметри | виконувані файли |
| Неперехоплений виняток у звичайному вхідному модулі | escript завершується з кодом 127 | Завершується з кодом 1 і одним рядком uncaught exception <class>: <reason> (вихідні файли escript зберігають 127) | виконувані файли |
| Діагностика компілятора | Формулювання erl_lint (variable 'X' is unbound) і попередження | Власні формулювання (unbound variable X); попередження lint з OTP здебільшого не видаються (також для невідомих полів native record у доступі, оновленні та зразках) | семантика |
Граничні випадки мови
| Відмінність | OTP | Clause | Власник |
|---|---|---|---|
Цілочисловий сегмент, ширший за межу цілих чисел, зі значенням понад неї (<<V:4194241>> з усіх одиниць) | JIT для x86 зіставляє з недійсним термом; його використання призводить до аварії VM | Немає збігу | терми |
| Zip-група, у якій нестрогий і строгий генератори мають спільну змінну | Перевірка пропуску зберігає змінні строгих зразків у нестрогих зразках | Відхилений крок пропускається щоразу, коли строгі зразки збігаються самі по собі | зразки |
Виклик зовнішнього fun, M:F(Args) або apply/3 модуля поза програмою | Завантажує модуль зі шляху коду, undef, якщо його немає | undef; бібліотечні модулі входять до програми лише тоді, коли вона називає їх літеральним атомом | fun, бібліотека |
lists і maps | Повні модулі; maps:keys/1, values/1, to_list/1, fold/3 дотримуються внутрішнього порядку map (порядок таблиці атомів для атомних ключів, порядок хешів понад 32 ключі) | Підмножина бібліотеки; функції map дотримуються порядку ключів | бібліотека |
Файли без #!, передані як escript | escript file.erl пропускає перший рядок | Компілюються як звичайні модулі | виконувані файли |
| Попередньо скомпільовані beam та архівні escript | Виконуються | Не підтримуються | виконувані файли |
-spec, типи якого не мають спільного значення з виведеним результатом, вхідною областю визначення чи аргументами виклику | Компілюється; Dialyzer може попередити | Помилка компіляції із зазначенням оголошених і виведених типів | семантичний аналіз |
io
| Відмінність | OTP | Clause | Власник |
|---|---|---|---|
Керувальні послідовності ~e ~f ~g ~x ~X ~+ ~# ~W ~P, модифікатор K | Форматуються | badarg | io |
~p для контейнерів із вкладеністю понад 256 рівнів | Друкуються | system_limit | io |
Ширина полів і точність ~ts з комбінованими символами або \r\n | Лічать кластери графем | Лічать кодові точки | io |
Від'ємна точність або кількість заповнення (~.*c з -1) | Нескінченний цикл | badarg | io |
Функції io, крім format/1,2, put_chars/1 | Існують | unknown module io | io |
Clause