Старые модели: что компилятор делает с прежней поверхностью
Эта глава нужна одному читателю: у которого на диске лежат файлы ранней
поверхности языка — с категория, объект, утилита, правило, свойство —
и который хочет знать, что с ними будет сегодня. Если таких файлов у вас нет,
главу можно пропустить: на язык она не влияет.
Что происходит, когда такой файл отдают компилятору
Разборщик эти слова знает. Он их читает и раскладывает в узлы ftsLegacy —
это часть языка, а не отдельный формат и не режим совместимости
(flang/SPEC.md, §9 «Наследие поверхности»).
Функций из них, однако, не получается. Файл, в котором есть только утилиты, —
не программа, и flang check отвечает отказом, называя, чем пользоваться
сейчас. Не «файл повреждён», не молчаливый ноль: отказ с указанием.
Практический вывод: старая модель не сломается в пути и не будет тихо считаться не тем — она честно не пройдёт.
Почему нет команды «перевести автоматически»
Перевод напрашивается: объект — в запись, утилиту — в тотальную функцию, свойства — в постусловия. Такого перевода в дереве нет, и это решение, а не недоделка.
Причина в том, что перевод получился бы правдоподобным, но не эквивалентным. Утилита старой поверхности вычисляла на динамических данных: поля приходили объектом, их наличие и тип проверялись во время исполнения, а несоответствие возвращалось диагностикой. Тотальная функция flang требует типов на этапе сборки — то, что раньше было ответом рантайма («во входных данных отсутствует поле «сумма»»), становится ошибкой компиляции или не возникает вовсе. Машина, которая переписала бы одно в другое, вынуждена была бы что-то выдумать: типы полей, поведение на отсутствующем поле, границы числа. Выдуманное выглядело бы как перенесённое.
Поэтому перенос — ручной, и об этом сказано прямо.
Таблица соответствий
| Прежняя поверхность | Сегодняшний flang | Что меняется по существу |
|---|---|---|
категория «Продажи» |
модуль или просто имя файла | группировка перестаёт быть конструкцией языка |
объект «Покупка» с полями |
объявление записи с типами полей | типы полей обязательны и проверяются при сборке |
утилита «Рассчитать скидку» |
тотальная функция «Рассчитать скидку» |
появляется обязанность доказать завершение |
правило внутри утилиты |
тело функции: если … иначе …, разбор … случай … |
ветвление становится выражением со значением |
свойство «…» |
обеспечивает «…» <утверждение> |
утверждение проверяет компилятор, а не рантайм |
пример … ожидается … |
пример … ожидается … |
не меняется ничего: примеры перешли как есть |
Единственная строка, которая переносится дословно, — примеры. Это не случайность: примеры-внутри-функции были удачной частью ранней поверхности и остались в языке без изменений.
Коды диагностик: почему в выводе встречается FTS_
Здесь легко ошибиться, поэтому точно.
У постусловия, объявленного словом обеспечивает в обычной функции flang, код
нарушения — FLANG_PROPERTY. У свойства утилиты наследия код свой —
FTS_UTILITY_PROPERTY, и он едет в дерево разбора данными: девять целевых
рантаймов обязаны выдать именно его, ничего про него не зная
(flang/SPEC.md, «Постусловия функции»).
То есть приставка FTS_ в выводе — не след старого компилятора, а честное
имя кода, закреплённое за конструкцией наследия. Увидели FTS_UTILITY_* —
значит считалась утилита старой поверхности. Увидели FLANG_PROPERTY — значит
функция сегодняшнего языка. Перепишете модель по таблице выше — коды сменятся
сами, во всех девяти целях печати.
Что от ранней поверхности осталось в языке по-настоящему
Не слова, а три решения, и они пережили переписывание компилятора:
Имена в ёлочках. «Рассчитать скидку» вместо calculateDiscount. Правило,
которое читает не только автор, должно называться так, как его называют в
предметной области.
Две равноправные поверхности. Русская и английская — не перевод документации, а два написания одного языка, дающие одно дерево разбора.
Примеры внутри функции. Тест лежит вплотную к коду, а не в файле, который забудут обновить.
Всё остальное — система типов, доказательство завершения, печать в целевые языки, поручения ввода-вывода — выросло уже в flang.
Если переписывать нечем
Бывает, что старая модель нужна работающей прямо сейчас, а времени на перенос нет. Тогда честный ответ такой: сегодняшний компилятор её не исполнит, и подпирать это самодельным разборщиком не стоит — он разойдётся с настоящим на редких конструкциях, и разойдётся молча.
Рабочий путь — перенести по таблице ту одну утилиту, которая нужна, и убедиться на её же примерах, что счёт сошёлся: примеры переносятся дословно, поэтому именно они и служат доказательством, что перенос не изменил поведения.