Incus J 10 Posted September 24, 2021 (edited) I have two classes (TClassA and TClassB) declared in separate units. Both have a class constructor which executes automatically when the app starts: type TClassB=class(TObject) class constructor Create; ... class constructor TClassB.Create; begin //Some class initialization code end Note that this is a class constructor, not a regular instance constructor. At present, when the app starts up TClassB's class constructor runs first, and then TClassA's class constructor follows afterwards. In this particular case I want the opposite to occur - I want TClassA to run its class constructor code before TClassB runs its class constructor. How can I achieve that? (I've tried swapping the order of the unit declarations in the Project source .dpr file, but that had no effect) Edited September 24, 2021 by Incus J Share this post Link to post
Incus J 10 Posted September 24, 2021 Thanks - although that didn't work, it did get me thinking more closely about what is actually happening: TClassA is a Controller that uses TClassB (Model), so B probably gets class construction priority. However although TClassB is unaware of TClassA (as it currently stands unitA uses unitB, but unitB does not use unitA) TClassA initialises a data storage path elsewhere that TClassB happens to use. I sense a restructuring is required. Share this post Link to post
Darian Miller 361 Posted September 24, 2021 41 minutes ago, Incus J said: Thanks - although that didn't work, it did get me thinking more closely about what is actually happening: TClassA is a Controller that uses TClassB (Model), so B probably gets class construction priority. However although TClassB is unaware of TClassA (as it currently stands unitA uses unitB, but unitB does not use unitA) TClassA initialises a data storage path elsewhere that TClassB happens to use. I sense a restructuring is required. You'll want to read through this thread: 1 Share this post Link to post
Incus J 10 Posted September 24, 2021 (edited) 3 hours ago, Darian Miller said: You'll want to read through this thread Oh - yes, thank you. Some time later: My head hurts. This line jumped out at me though: Quote Enforcing dependencies in initialisation order is not robust. I prefer to find a different way to solve such problems. Based on what I've just read I think I might abandon trying to get TClassA to initialise before TClassB, and find another approach where it no longer matters which order the classes get initialised in. Yet somehow I've got to get that data storage path initialised before TClassB initialises - but since the path will be used by other classes too, I can't really do the obvious and get TClassB to initialise the path itself. Edited September 24, 2021 by Incus J Share this post Link to post
Darian Miller 361 Posted September 24, 2021 5 minutes ago, Incus J said: This line jumped out at me though Same here.. which is why I followed-up with a message to David today. Share this post Link to post
Incus J 10 Posted September 24, 2021 I guess I could modify things so neither class initialises at startup. And have some separate custom startup routine that explicitly initialises each class in the order I desire. But to make that work I'd need to give each class a non-standard class initialisation method (i.e. not called Create) for me to call. Which seems a bit ugly. Definitely interested to hear David's thoughts! Share this post Link to post
Dave Novo 51 Posted September 25, 2021 Make the storage data path (TDataStoragePath) a singleton object that initializes itself with the path. All other units that need the path will have to use the unit where TDataStoragePath is defined hence will force TDataStoragePath to initialize first. 1 Share this post Link to post
Guest Posted September 25, 2021 16 hours ago, Incus J said: How can I achieve that? (I've tried swapping the order of the unit declarations in the Project source .dpr file, but that had no effect) In many project i have a singleton logger, and always i want it to be the first of everything to be initialized even before the configurator singleton, which responsible for the logger behaviour, my logger will buffer everything in memory specially the configurator messages and even the dpr messages, when the configurator initialized and have the settings for the logger, then the logger will act based on the settings, what it is, if it to drop the buffer and log nothing then will clear its memory and skip the following messages, if it to save to file then it will flush its memory saved logs to disk and will save following messages to disk directly, or if it is keep in memory until something goes wrong and flush to disk then... Anyway logger must be the first, and i do the following as workaround type TClassX = class // we need this to be after A nd B class var Identifier: Integer; class constructor Create; end; TClassA = class class var Identifier: Integer; class constructor Create; end; TClassB = class class var Identifier: Integer; class constructor Create; end; TClassC = class class var Identifier: Integer; class constructor Create; end; { TClassX } class constructor TClassX.Create; begin //Identifier := TClassA.Identifier + TClassB.Identifier; // will initialize A then B first //Identifier := TClassB.Identifier + TClassA.Identifier; // will initialize B then A first Writeln('ClassX constructor'); end; { TClassB } class constructor TClassB.Create; begin //Identifier := TClassA.Identifier; // hint the compiler to initialize A first Writeln('ClassB constructor'); end; { TClassC } class constructor TClassC.Create; begin //Identifier := TClassB.Identifier; // hint the compiler to initialize B first Writeln('ClassC constructor'); end; { TClassA } class constructor TClassA.Create; begin Writeln('ClassA constructor'); end; var A: TClassA; B: TClassB; C: TClassC; X: TClassX; begin X := TClassX.Create; C := TClassC.Create; B := TClassB.Create; A := TClassA.Create; try finally C.Free; B.Free; A.Free; X.Free; end; Readln; end. the result for the above is Quote ClassX constructor ClassB constructor ClassC constructor ClassA constructor by uncommenting the commented above in B and C Quote ClassX constructor ClassA constructor ClassB constructor ClassC constructor by uncommenting the second commented line in X constructor, we have Quote ClassB constructor ClassA constructor ClassX constructor ClassC constructor try to play around and see the effect of such approach, just keep in mind there is no warning of cycle usage it will only bring us back to the unpredictable. The class var in this approach (workaround) have zero effect on the code or its performance. Share this post Link to post
Incus J 10 Posted September 27, 2021 Thanks Dave and Kas - some really neat approaches there - I will give them a try! Share this post Link to post
Fr0sT.Brutal 900 Posted September 27, 2021 Maybe you could use lazy init so the class' state will be independent of c-tor call order? TClassSmth = class private class function GetProp public class c-tor Create property Prop read GetProp end class c-tor TClassSmth.Create GetProp end class function TClassSmth.GetProp if not Assigned(FProp) then Init(FProp) Exit(FProp) end Share this post Link to post