wuwuxin 28 Posted August 31, 2021 I am somewhat unclear about Delphi class constructor. Say, for the following code: TMyFunkyObject = class strict private class constructor Create; public class procedure FoBar; end; I am calling TMyFunkyObject.FoBar from the initialization section of another unit. Is it guaranteed that the class constructor will be (implicitly) called before TMyFunkyObject.FoBar? Or the sequence is in-deterministic? Share this post Link to post
David Heffernan 2345 Posted August 31, 2021 Class constructors are called from the initialization section of the unit where the class is declared. So in your scenario it depends on the initialization order, and therefore it is not guaranteed that the class constructor is called before class methods are called. Share this post Link to post
Lars Fosdal 1790 Posted August 31, 2021 A generic class constructor can behave even weirder. https://docwiki.embarcadero.com/RADStudio/Sydney/en/Methods_(Delphi)#Class_Constructors Quote Note: Even though the compiler takes care of ordering the initialization of classes, in some complex scenarios, ordering may become random. This happens when the class constructor of a class depends on the state of another class that, in turn, depends on the first class. Note: The class constructor for a generic class or record may execute multiple times. The exact number of times the class constructor is executed in this case depends on the number of specialized versions of the generic type. For example, the class constructor for a specialized TList<String> class may execute multiple times in the same application. 1 1 Share this post Link to post
Fr0sT.Brutal 900 Posted August 31, 2021 *facepalm* is it really so hard to run init sections in the order of unit appearance? 1 Share this post Link to post
Lars Fosdal 1790 Posted August 31, 2021 Circular references create a lot of fun. 1 1 Share this post Link to post
M.Joos 30 Posted August 31, 2021 From an old blog post from Allen Bauer (https://blog.therealoracleatdelphi.com/2009/09/: " All eligible class constructors and class destructors are invoked in sequence with unit initialization and finalization, respectively. If a given class constructor or destructor is eligible to be invoked (ie. it was linked into your application), it will run immediately before the initialization section for the unit in which the class is implemented. The class destructors will be invoked immediately after the finalization section for the unit in which the class is implemented. Class constructors in a given unit are generally invoked in the same order of declaration, except in cases described below. Class destructors are invoked in reverse order from the class constructors. For an ancestor class declared in the same unit, its class constructor will be invoked before the descendant class constructor and the class destructor is invoked after the descendant class destructor. If the implementation of given class constructor references another class in the same unit with a class constructor, the referenced class’ class constructor will be invoked before the current class’ class constructor. If the references are cyclic (ie. they reference each other in their class constructors), then they are invoked in reverse order of declaration. This means that there can be cases where a class constructor can reference an “unconstructed” class. Ancestor classes from external units used in the interface section are guaranteed to already have their class constructors run prior to any class constructors on descendant classes within the current unit. Unit cycles can break down the deterministic nature of the above rules in the same manner as unit initialization and finalization. However, for a given unit, it is guaranteed that all the class constructors declared within in it will have already run immediately before the initialization section runs. Congruent to this rule is that it is guaranteed that all the class destructors will run immediately after the finalization section. Dynamically loaded packages, using LoadPackage. Because there is no way to know exactly which classes are going to be used, just like there is no way to know which units are going to be used, all class constructors and destructors along with all unit initialization and finalizations are invoked according to the above rules. Other rules about their use are: You do not have to declare a class destructor if you declare a class constructor, and vice versa. They cannot be virtual, dynamic or message. They cannot be explicitly called. They cannot have any parameters. They do not have to be called Create and Destroy. (ie. Init and Fini are equally valid names). With this implementation, it was easier to leverage the same table that the compiler creates for unit initialization and finalization. It satisfies this requirement: “Called automatically to initialize the class before the first instance is created or any static members are referenced.” Issues with cycles are also clearly warned against in VB.NET and C#: “Avoid circular references in Shared … since it is generally impossible to determine the order in which classes containing such references are loaded.” Another benefit is that since it is running during the initialization/finalization phases, any threading implications are no different than the existing rules regarding unit initialization and finalization." What we don't know is, if the compiler behavoiur has changed since then. 2 2 Share this post Link to post
wuwuxin 28 Posted August 31, 2021 16 hours ago, David Heffernan said: So in your scenario it depends on the initialization order, and therefore it is not guaranteed that the class constructor is called before class methods are called. @David Heffernan Thanks you. If Unit A is where the class (that has a class constructror) is defined, and Unit B is where the static class method is called (in Unit B's initialization section) - that is, Unit B references Unit A. Does that mean Unit A initialization come BEFORE unit B? Share this post Link to post
David Heffernan 2345 Posted August 31, 2021 1 hour ago, wuwuxin said: @David Heffernan Thanks you. If Unit A is where the class (that has a class constructror) is defined, and Unit B is where the static class method is called (in Unit B's initialization section) - that is, Unit B references Unit A. Does that mean Unit A initialization come BEFORE unit B? Not necessarily. For instance if your dpr file references them in the other order then it won't be that way. And other unit use clauses can confound you. Enforcing dependencies in initialisation order is not robust. I prefer to find a different way to solve such problems. 1 Share this post Link to post
Guest Posted September 1, 2021 On 8/31/2021 at 9:41 AM, Fr0sT.Brutal said: *facepalm* is it really so hard to run init sections in the order of unit appearance? Sometimes when juggling multiple mt-enabled 3rd party libs it is an absolute necessity. Just include units (from different libs, own code et.al) in the dfm, in the needed order and put a comment in the dfm to explain why this is key. Also - (slightl unrelated) - always minimize the IDE "auto dfm stuff" like managing main form(s). IMHO any IDE "help" is just for introduction. Serious projects should not allow the IDE to edit code at all if not specifically requested by the dev. Share this post Link to post
David Heffernan 2345 Posted September 2, 2021 15 hours ago, Dany Marmur said: Sometimes when juggling multiple mt-enabled 3rd party libs it is an absolute necessity. Just include units (from different libs, own code et.al) in the dfm, in the needed order and put a comment in the dfm to explain why this is key. Also - (slightl unrelated) - always minimize the IDE "auto dfm stuff" like managing main form(s). IMHO any IDE "help" is just for introduction. Serious projects should not allow the IDE to edit code at all if not specifically requested by the dev. I guess you mean dpr not dfm. But even that sometimes is not enough. Because the units won't be initialised in the order the appear in the dpr. The first unit in the dpr will use other units and that influences initialisation order too. Share this post Link to post
Bill Meyer 337 Posted September 2, 2021 On 8/31/2021 at 2:43 AM, Lars Fosdal said: Circular references create a lot of fun. You have a twisted sense of humor, sir. 😉 Share this post Link to post
Lars Fosdal 1790 Posted September 3, 2021 17 hours ago, Bill Meyer said: You have a twisted sense of humor, sir. 😉 It exists to balance out my inherent sense of imminent doom. 3 Share this post Link to post
Guest Posted September 3, 2021 On 9/2/2021 at 8:54 AM, David Heffernan said: I guess you mean dpr not dfm. But even that sometimes is not enough. Because the units won't be initialised in the order the appear in the dpr. The first unit in the dpr will use other units and that influences initialisation order too. Yes, i did dfm, and very true. It's not a perfect strategy. Thanks for the clarification. Share this post Link to post
Bill Meyer 337 Posted September 3, 2021 6 hours ago, Lars Fosdal said: It exists to balance out my inherent sense of imminent doom. I see. But that sense of doom is just a constant. 1 Share this post Link to post
Darian Miller 361 Posted September 24, 2021 On 8/31/2021 at 6:39 PM, David Heffernan said: Enforcing dependencies in initialisation order is not robust. I prefer to find a different way to solve such problems. I was thinking about this thread today and was curious - what is your different way to solve the initialization order problem? Share this post Link to post
David Schwartz 426 Posted September 27, 2021 On 9/24/2021 at 10:50 AM, Darian Miller said: I was thinking about this thread today and was curious - what is your different way to solve the initialization order problem? You're trying to use a default mechanism that was defined for the convenience of the IDE and basic run-time system. If it doesn't work for some of your units or objects, you'd probably want to somehow "register" your objects that have an ordering dependency with something of your own creation (a dictionary or directory of some kind), then initialize them in whatever order you need. Similar to what you'd get using a DI container. Share this post Link to post
FreeDelphiPascal 19 Posted September 24 Rudy Velthuis said on SO that "Class constructors are not executed on unit "initialization" but when the class is referenced" Share this post Link to post
Anders Melander 1780 Posted September 24 59 minutes ago, FreeDelphiPascal said: Rudy Velthuis said on SO that "Class constructors are not executed on unit "initialization" but when the class is referenced" He was wrong. 1 Share this post Link to post
Brandon Staggs 272 Posted September 24 5 hours ago, FreeDelphiPascal said: Rudy Velthuis said on SO that "Class constructors are not executed on unit "initialization" but when the class is referenced" By itself, that statement isn't correct. I didn't read the original post for context, but maybe he was talking about the fact that a class constructor is not called unless the class is referenced in compiled code, unlike initialization sections in units, which are always executed regardless of anything else in the unit being used or not. Share this post Link to post
David Heffernan 2345 Posted September 24 5 hours ago, FreeDelphiPascal said: Rudy Velthuis said on SO that "Class constructors are not executed on unit "initialization" but when the class is referenced" Please provide a link to this post and if it's wrong then we can correct it. Or perhaps you didn't interpret it correctly. Share this post Link to post
FreeDelphiPascal 19 Posted September 25 (edited) 11 hours ago, David Heffernan said: Please provide a link to this post and if it's wrong then we can correct it. Or perhaps you didn't interpret it correctly. Yeah, my interpretation was wrong. It doesn't exactly makes the connection (or disconnection) between the class constructor and the initialization section. The exact quote is: "Note that a class constructor only executes if the class is used. So unlike a normal initialization section of a unit (which always executes), it only executes if the class is used somewhere." Yesterday I was reading more about class conductors, and I see his statement in a new light. I think, to this point, the https://blog.therealoracleatdelphi.com/2009/09/ is still the best resource available about class constructors. https://stackoverflow.com/questions/39471864/delphi-constructor-and-class-constructor Edited September 25 by FreeDelphiPascal 1 Share this post Link to post
Rollo62 534 Posted September 25 In some rare cases I add a "Module_Init();" function in such units, which can be called from the caller unit or initialization process, to have a little bit better manual control over the initialization order. Share this post Link to post
Uwe Raabe 2056 Posted September 25 CmonLib Initializing provides a way to register a procedure to be called during Application.Initialize. This allows to make adjustments before (f.i. in the dpr file or some units), which would be near to impossible if the initialize code would execute in the units initialization section. 1 Share this post Link to post
Rollo62 534 Posted September 25 (edited) Some more details on CmonLib TInitialize here too https://en.delphipraxis.net/topic/11986-best-way-to-set-early-global-variables-in-a-project-before-build-time/ Edited September 25 by Rollo62 Share this post Link to post