Информация об изменениях

Сообщение Re[5]: Языки программирования через 10 лет от 13.03.2015 7:18

Изменено 13.03.2015 7:51 Философ

Здравствуйте, Aleх, Вы писали:

A>Здравствуйте, Философ, Вы писали:


Ф>>Да, говно, но не поэтому (не из-за var блока и не из-за скобочек).


Ф>>Из-за модульной парадигмы (namespace'ов приделанных сбоку, unit vars, initialization/finaliztion), из-за наследования конструкторов, и тучи других причин масштабом поменьше.


A>Имеется ввиду конкретная реализация модульной парадигмы или же модули vs заголовочные файлы?


Имеется ввиду сложность предсказания потока исполнения: слишком сложно сказать в каком порядке будут исполнены секции initialization/finalization а от этого может многое зависеть, т.к. там иногда переопределяются некоторые глобальные вещи, типа функций управления памятью. В делфе процветает чёрная магия.
Re[5]: Языки программирования через 10 лет
Здравствуйте, Aleх, Вы писали:

A>Здравствуйте, Философ, Вы писали:


Ф>>Да, говно, но не поэтому (не из-за var блока и не из-за скобочек).


Ф>>Из-за модульной парадигмы (namespace'ов приделанных сбоку, unit vars, initialization/finaliztion), из-за наследования конструкторов, и тучи других причин масштабом поменьше.


A>Имеется ввиду конкретная реализация модульной парадигмы или же модули vs заголовочные файлы?


1)
Имеется ввиду сложность предсказания потока исполнения: слишком сложно сказать в каком порядке будут исполнены секции initialization/finalization а от этого может многое зависеть, т.к. там иногда переопределяются некоторые глобальные вещи, типа функций управления памятью. В делфе процветает чёрная магия.

Даже если ты точно сможешь сказать, что секции initialization будут выполнены в том порядке, в котором указаны модули в файле проекта, то о необходимости блюсти этот порядок посторонний разработчик может и не знать. Ловить потом баги порождённые этим очень сложно долго.

2) Такая парадигма крайне плохо дружит с многопоточностью. Вот, представь:

  code
//файл проекта---------------------------------------------------
program ThisProgramDemonstrateFuckingShitFromDephiWorld;
uses MyFuckignUnit,
    MyFuckignUnit2;
begin
  WriteLn('Hello from delphi hell');
end.


//файл модуля---------------------------------------------------
unit MyFuckignUnit;

interface
uses SysUtils, MyFuckignUnit2, MyFuckignUnit3;

implementation
function CreateMyObjectWithThreads() :TObject;
begin
  //here creating object that uses threads
end;

var o :TObject;
initialization
o := CreateMyObjectWithThreads();

finalization
 FreeAndNil(o);
end.

//файл модуля---------------------------------------------------
unit MyFuckignUnit2;
interface
 procedure UseModuleVar();

implementation
procedure UseModuleVar();
begin
 moduleVar := false;
end;

var moduleVar :boolean;
initialization
  moduleVar := true;
finalization


В коде показана ситуация, когда во время инициализации модуля 1 создаётся объект, который создаёт и использует поток (пусть это будет неявно). Из потока читается булевская переменная из модуля 2, которая там инициализируется в секции инициализации. Никакого криминала в незащищённом чтении булевской переменной нет — это атомарная операция. Косяк здесь в том, что поток может её прочитать до того, как она была выставлена в правильное значение — всё, ты попал на часы нудной отладки.
С потоками всё значительно сложнее потому, что распределение квантов времени ты предсказать не можешь: в одном случае переменная уже будет выставлена, а в другом нет.
Даже если без потоков, просто до инициализации модуля дело ещё не дошло, но уже оттуда зовутся функции ситуация оказывается подобной, хотя и проще.