Хак для упорядочивания initialization

Планы, идеология, архитектура и т.п.

Модератор: Модераторы

Хак для упорядочивания initialization

Сообщение runewalsh » 08.04.2018 02:24:35

Давно столкнулся с проблемой задания явного порядка initialization. Задумавшись снова, кое-что придумал ^^
https://github.com/runewalsh/fpc-unit-prioritizer

Пример использования:
UnitA.pas
Код: Выделить всё
unit UnitA;

interface

uses
   Prioritizer;

implementation

initialization
   RegisterUnit('UnitA', +1);
   writeln('UnitA(+1) инициализирован');
end.

UnitB.pas
Код: Выделить всё
unit UnitB;

interface

uses
   Prioritizer;

implementation

initialization
   RegisterUnit('UnitB', 0);
   writeln('UnitB(0) инициализирован');
end.

UnitC.pas
Код: Выделить всё
unit UnitC;

interface

uses
   Prioritizer;

implementation

initialization
   RegisterUnit('UnitC', -1);
   writeln('UnitC(-1) инициализирован');
end.

main.pas
Код: Выделить всё
uses
   UnitB, UnitC, UnitA;

begin
end.

— вызовет секции initialization в порядке UnitA → UnitB → UnitC, независимо от чьего бы то ни было порядка подключения или взаимных зависимостей.

Решение опирается на недокументированные структуры и гвоздями прибито к каким-то платформам и версиям FPC, так что не думаю, что вызовет интерес помимо академического. Но однозначно буду использовать сам, т. к. до этого строил список модулей, которому руками нужно было дёрнуть SortAndInitialize в начале основной программы, что ну очень неудобно.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Хак для упорядочивания initialization

Сообщение olegy123 » 08.04.2018 07:34:18

а если попробовать так
uses
UnitA, UnitB, UnitC ;


очень важно чтобы UnitA, UnitB, UnitC больше нигде не светились в других модулях, даже в *.lpr или были обработаны в таком же порядке.

runewalsh писал(а):Решение опирается на недокументированные структуры и гвоздями прибито к каким-то платформам и версиям FPC, так что не думаю, что вызовет интерес помимо академического. Но однозначно буду использовать сам, т. к. до этого строил список модулей, которому руками нужно было дёрнуть SortAndInitialize в начале основной программы, что ну очень неудобно.

я думаю, что модули строятся в порядке их описания. Потому, что необходимы перекрытия.

interface
[публична видна везде, не допустимы перекрестные зависимости]
implementation
[локальна видна везде, допустимы перекрестные зависимости - они не видны друг другу]
initialization/finalization
[глобальна, только выполняется 1 раз]


Есть стек FIFO модулей, отсюда инициализация выполняется в зависимости поступления в этот стек FIFO. Тут нет никакой магии.

Добавлено спустя 3 минуты 41 секунду:
runewalsh писал(а):SortAndInitialize
не думаю что нужно, проще описать инициализирующую функцию, которая бы вызывалась бы вначале lpr.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Хак для упорядочивания initialization

Сообщение zub » 08.04.2018 07:42:03

>>Тут нет никакой магии.
Магия начинается при появлении зацикленых uses. Сталкивался с разным порядком инициализации в delphi и fpc - ничего тогда сделать не получилось((

Предлагаемое решение конечно жесть)) гораздо правильней в таких случаях пересмотреть архитектуру и избавится от зацикливаний
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Хак для упорядочивания initialization

Сообщение runewalsh » 08.04.2018 08:00:32

Инициализирующую функцию можно случайно не вызвать, а порядок, выстроенный компилятором, не очевиден и может сбиться в ходе безобидного рефакторинга или удаления «неиспользуемых» модулей, в том-то и дело.
У проблем, возникающих из-за требований к порядку инициализации модулей, всегда есть более красивые решения. Просто иногда так проще.

Представь, что модуль A предоставляет синглтон-пул неких объектов, который инициализируется при первом обращении, а уничтожается в finalization.
Представь, что модуль B выделяет объект из этого пула и в своём finalization возвращает назад.
Представь, что к моменту возвращения пул оказывается уничтожен. Тогда он посчитает это первым обращением, создастся снова и уже не уничтожится.

Такого плана проблемы могут быть, если твой код не идеален, а он никогда не идеален =3, и иногда проще всего решаются именно выставлением приоритетов «какими они задумывались», а не как получилось в uses.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Хак для упорядочивания initialization

Сообщение Awkward » 08.04.2018 08:12:24

А может, пойти по пути наименьшего сопротивления, если все модули с инициализацией - "наши" кастомные? сделать один глобальный модуль, где прописать структуру для регистрации процедур инициализации, в секции инициализации каждого модуля прописать "регистрацию" в той структуре, а потом, в основном модуле вызвать свою функцию, которая уже отсортирует эти инициализационные как надо и вызовет их в нужном порядке? Так будет "документировано" по крайней мере.
Awkward
новенький
 
Сообщения: 48
Зарегистрирован: 19.01.2017 00:06:47

Re: Хак для упорядочивания initialization

Сообщение runewalsh » 08.04.2018 08:25:30

Это мой первоначальный вариант с «дёргать руками SortAndInitialize». Я решил плюнуть на чистоту подхода, потому что каждый новый проект стабильно начинаю с того, что забываю её вызвать =( Ну и менее удобно из-за худшей семантичности: функции ещё какие-то объявлять, вместо тех же действий непосредственно в init/final.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Хак для упорядочивания initialization

Сообщение olegy123 » 08.04.2018 08:26:45

Awkward писал(а):А может, пойти по пути наименьшего сопротивления, если все модули с инициализацией - "наши" кастомные? сделать один глобальный модуль

такой файл уже есть - LPR

runewalsh писал(а):Такого плана проблемы могут быть, если твой код не идеален, а он никогда не идеален =3, и иногда проще всего решаются именно выставлением приоритетов «какими они задумывались», а не как получилось в uses.

Публикуйте unit в LPR в нужном порядке.. а не где-то там в блоках.

https://stackoverflow.com/questions/230 ... -in-a-unit

runewalsh писал(а):Инициализирующую функцию можно случайно не вызвать, а порядок, выстроенный компилятором, не очевиден и может сбиться в ходе безобидного рефакторинга или удаления «неиспользуемых» модулей, в том-то и дело.

очевиден, он очевиден и компилятору.. то что вы хотите сделать - выльется в итоге в двух, а при финиализации в трехпроходность компилятора.

Добавлено спустя 7 минут 57 секунд:
zub писал(а):Магия начинается при появлении зацикленых uses. Сталкивался с разным порядком инициализации в delphi и fpc - ничего тогда сделать не получилось((

магии нет - есть компилятор, в лексоре при чтении кода формируются списки имен и их смысл, строятся ссылки и их зависимости. Не думаю, что порядок выполняется случайным образом, а не по мере поступления кода..
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Хак для упорядочивания initialization

Сообщение runewalsh » 08.04.2018 08:37:42

>Это мой первоначальный вариант с «дёргать руками SortAndInitialize».
Алсо, пример «было» — «стало». Ну няшка же? Няшка. Хоть и сломается когда-нибудь.
1.png
2.png
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Хак для упорядочивания initialization

Сообщение Cheb » 09.04.2018 13:57:11

Сама идея настолько порочна -- одно из худших мест в паскале -- , что приходится ручками брать и переделывать сторонние модули, вырезая из них этот сраный Initialization. Хотя бы тот же opengl. Потому что иначе это превращается в ктулхообразное болото.
А у меня просто: движок использует длл в линуксе, где Initialization просто не срабатывает. Ну, или, раньше так было - не проверял с версии fpc 1.9.8.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: Хак для упорядочивания initialization

Сообщение pupsik » 09.04.2018 14:04:31

runewalsh я верно понимаю: необходима "инициализация" в каждом модуле?
pupsik
энтузиаст
 
Сообщения: 1154
Зарегистрирован: 20.08.2014 16:20:13

Re: Хак для упорядочивания initialization

Сообщение runewalsh » 09.04.2018 14:48:28

Нет, модуль может просто ничего нового не делать, такие инициализируются в первую очередь (т. е. как обычно), а все с приоритетами — во вторую.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Хак для упорядочивания initialization

Сообщение pupsik » 09.04.2018 15:06:58

Вы не поняли...

Код: Выделить всё
писать в каждом, при необходимости?
initialization
   RegisterUnit('UnitC', -1);
   writeln('UnitC(-1) инициализирован');


Добавлено спустя 7 минут 32 секунды:
Т.е.: нет возможности глобально решить данный вопрос в приложении?
pupsik
энтузиаст
 
Сообщения: 1154
Зарегистрирован: 20.08.2014 16:20:13

Re: Хак для упорядочивания initialization

Сообщение runewalsh » 09.04.2018 15:18:24

Ну да, нужно же как-то сообщить приоритет. Я не придумал другого способа убить двух зайцев. А именно, что делает RegisterUnit:
— сообщает «наверх» информацию о модуле (приоритет), initialization которого сейчас выполняется;
— тут же прерывает инициализацию модуля (бросая специальное исключение) — позже она вызовется ещё раз в нужном порядке и RegisterUnit станет no-op'ом.

Глобальным решением была бы поддержка со стороны компилятора, но такого, к счастью, не будет.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Хак для упорядочивания initialization

Сообщение pupsik » 09.04.2018 15:40:13

По идее глобально позволит в одном месте делать "каку", не заботясь о склерозе.
По модулям... В чём "няшка" то? Как было, так и осталось. "Тыкать" каждый модуль (требуемый).

п.с
возможно и ошибаюсь.
pupsik
энтузиаст
 
Сообщения: 1154
Зарегистрирован: 20.08.2014 16:20:13

Re: Хак для упорядочивания initialization

Сообщение zub » 09.04.2018 19:28:16

runewalsh писал(а):Представь, что модуль A предоставляет синглтон-пул неких объектов, который инициализируется при первом обращении, а уничтожается в finalization.
Представь, что модуль B выделяет объект из этого пула и в своём finalization возвращает назад.

Описаная ситуация вполне решается компилятором, единственное условие необходимое для этого - отсутствмие implementation uses и соответственно циклических ссылок.
Топик - борьба с последствиями (и зло в чистом виде ИМХО :D ), велосипедики и костылики нужно направлять на уход от implementation uses, благо это можно сделать и красиво и полностью компилеронезависимо
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

След.

Вернуться в Разработки на нашем сайте

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Рейтинг@Mail.ru