flang компилятор доказывает, что программа не зациклится 0.6.2 GitHub

Решение о мире переносимо, даже когда сам мир — нет: у слоя связи узла это 554 строки против 42

Когда про кусок кода говорят «он трогает мир, значит на flang не пишется», почти всегда меряют ФАЙЛ. А в файле мир и решение о мире лежат вперемешку, и пропорция бывает какая угодно.

У слоя связи распределённого узла она такая. Замер снят 20 августа по создатьУзел, строки 320–915 тогдашнего файла (flang/conc/distributed.mjs, 1062 строки на конец дня): в тех 596 строках 42 трогают мир, и все 42 одного из восьми видов: createConnection, createServer, write, destroy, on, setInterval, setTimeout, Date.now. Остальные 554 — решения О сокете и О часах.

Признак, по которому это различается заранее. Возьмите правило и спросите, что у него на входе и на выходе. «Связь молчит дольше срока — считать её потерянной»: на входе две отметки часов и число, на выходе да или нет. Мира нет. «Прочитать, сколько сейчас времени»: мир. Первое переносимо, второе — нет, и никакая изобретательность этого не изменит.

Это та же граница, по которой в языке уже проведён ввод-вывод: поручение ОПИСЫВАЕТ программа, исполняет хозяин. Здесь то же самое сказано в другую сторону: событие мира ОПИСЫВАЕТ хозяин, а что из него следует — решает программа.

Чем подтверждено. flang/conc/link.flang — 400 строк, 11 событий мира, 8 велений хозяину, одна функция «Шаг связи» вместо семи замыканий свидетеля. Настоящий узел её ЗОВЁТ, а не повторяет (flang/conc/link.js — напечатанный модуль, ввозится в distributed.mjs), и по нему зелены 13 прогонов flang/conc/distributed.test.mjs, где два узла говорят по настоящим сокетам, провод перекусывают и замораживают.

Улика, что связь не бумажная: убери из эталона одну строку — сравнение молчания со сроком — и краснеет ровно один названный прогон, «провод заморожен: отказ объявлен по сроку, а не по событию сети». Убери правило «об этом разрыве уже доложено» — краснеют все восемь целей в flang/test/svyaz-celi.test.mjs.

Переносимость решения: 8 целей печати, 1032 вопроса каждой (32 состояния связи — все 16 сочетаний признаков на два значения отметки часов — × 16 событий × 2 положения «работает»), 8256 сверок, расхождений 0. Ветка vypusk/sokety-i-chasy, 20 августа 2026.

Цена второй цели предъявлена программой, а не оценкой. flang/conc/bin/peer.py — конец связи на цели python: 182 строки кода, из них трогают мир 13, решений ноль. Он звонит настоящему узлу на JavaScript, доводит рукопожатие, шлёт письмо (оно меняет состояние процесса на той стороне), получает ответное — и объявляет связь потерянной сам.

Часы на второй цели проверены единственным способом, каким их можно проверить, — МОЛЧАНИЕМ. Разрыв сокета заметен без часов, он приезжает событием; молчание не приезжает ничем, и заметить его можно, только сравнив две отметки со сроком. Поддельный сосед поздоровался верным хэшем и замолк, оставив сокет открытым: Python объявил потерю через 605 мс при сроке 600, текстом эталона — «молчание 601 мс при сроке 600 мс». Таких строк шим не строит вовсе.

Чем ограничено, и это важнее успеха. Переносимость решения — не работающий УЗЕЛ. Работает слой связи, а таблица процессов и планировщик остались на одной цели. Хозяин (сокеты, таймеры, часы) по-прежнему пишется на каждую цель; изменилась его цена — вместо «вывести 554 строки правил заново» это «10 переводов события и 7 исполнений веления», и правила при этом одни и те же на всех, потому что напечатаны из одного места.

И вторая половина узла — таблица процессов с планировщиком, 219 строк кода — этим приёмом не берётся: она не решает о мире, она ЕСТЬ планировщик.

Связано: distribution-splits-into-world-and-wire, a-node-cannot-be-an-ordinary-program-because-of-the-literal-addressee, cikl-porucheniy-prinadlezhit-hozyainu-a-ne-yazyku


Поправка от 20 августа. Последний абзац — «вторая половина узла… этим приёмом не берётся: она не решает о мире, она ЕСТЬ планировщик» — неверен, и это показано тем же приёмом, каким снята предыдущая поправка: пересчётом по строкам вместо оценки по существу.

Тот же блок (flang/conc/distributed.mjs, строки 380–683) — 224 строки кода, из которых мира ПЯТЬ: setImmediate, три setTimeout и два чтения часов. Остальные 219 — решения.

Ошибка в рассуждении была в том, что «есть планировщик» принималось за свойство КОДА. Это свойство того, кто ДЕРЖИТ УПРАВЛЕНИЕ. У планировщика ровно две вещи, которых в языке нет: чтение часов (мир) и вызов обработчика по имени (граница языка, не мир). Убери их — останутся решения, и они печатаются, как печатаются решения о связи.

Сделано: flang/conc/scheduler.flang, 506 строк, мира ноль, 7 событий хозяина и 6 велений хозяину. Печатается во все восемь целей — 8468 вопросов каждой, 67 744 сверки, расхождений 0. Полный узел (таблица процессов, планировщик и связь) работает на трёх целях из восьми: js, python, go, — и проверен настоящим рукопожатием, письмом через провод и ответом обратно.

Подробности и то, чем это ограничено, — the-node-scheduler-is-portable-219-decisions-of-224-lines.