Hi Delphiers
Hi Delphiers,
I see that a DPR unit cannot have a finalization section.
Does it look relevant to perform some global objects cleaning like this :
Program MyProgram;
Uses
....
{$R *.res}
Begin
MyObject := TMyObject.Create();
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm2, Form2);
Application.Run;
MyObject.Free(); // <------- This !
End.
I see that a DPR unit cannot have a finalization section.
Does it look relevant to perform some global objects cleaning like this :
Program MyProgram;
Uses
....
{$R *.res}
Begin
MyObject := TMyObject.Create();
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm2, Form2);
Application.Run;
MyObject.Free(); // <------- This !
End.
yes it is the usual way, but use try-finally statement
ReplyDeleteall initialization sections are executing after "begin" in dpr, and all finalization sections before "end" in dpr file, in the order they are included in dpr "uses" section
+1 for try-finally
ReplyDeleteOK Thanks .
ReplyDeleteSo my final code will look like this :
Begin
{$WARN SYMBOL_PLATFORM OFF}
System.ReportMemoryLeaksOnShutdown := DebugHook <> 0;
{$WARN SYMBOL_PLATFORM ON}
Try
Application.Initialize;
Application.CreateForm(TFMain, F_Main;
BootStrap(); // global objects creation
Application.Run;
Finally
Finalisation(); // global objects liberation
End;
End.
That's because the DPR isn't a unit :)
ReplyDeleteRegards,
A
Andrea Raimondi My dog doesn't bark because it's not a dog. Sounds logical :)
ReplyDeleteWhat I meant is, it's not a unit, it's a program file.
ReplyDeleteI am pretty sure you already were one of us back when this was a pivotal distinction, therefore I won't revel in it.
Anyhow, that's why it doesn't have initialization and finalization clauses.
A
Andrea Raimondi I might have been misunderstood : I wasn't denigrating your answer, I was just joking about the merciless logic aspect of your answer : in short : the dpr unit has no finalization because it is not an unit .... ;)
ReplyDeleteOlivier SCHWAB Read with care -- the dpr file is not a unit. It begins with the word program, not unit. It is a meaningful distinction. ;)
ReplyDeleteOlivier SCHWAB Please note that I said "The DPR" without specifying Unit just because, well, it is not a unit :)
ReplyDeleteBill Meyer In fact, in my 1 year experience in Delphi, I never considered really this file which is auto-generated ....
ReplyDeleteOlivier SCHWAB One year? I tend to consider everybody "old school" because, well, most of us come from years and years of using Delphi.
ReplyDeleteIf you are a new one, though, it will be a good thing that someone explains you why the program file is not a unit :)
You see, back in the TP days, the Program file would be your main execution file with units being your additional modules.
There was no direct way to tell a main file apart, except the use of the keyword "Program" :)
A
Andrea Raimondi 1 year of Delphi, but more than 10 years of various other languages, mainly C#. And I understand that is somehow an equivalent of main() . Thank you for the explanation, anyway !
ReplyDeleteI think it is a really bad idea to put hand-generated code in the DPR. Let Delphi do its thing here and put your runtime code where it belongs: in separate units. Various add-on IDE wizards and Delphi itself does not expect any extra code to reside in the DPR and will happily trounce it completely or screw it up in spectacular ways. I've been there, done that and got the tee-shirt to prove it.
ReplyDeleteKevin McCoy Sometimes you need to add code lines in DPR by hand, for example, when you add a customized splash, or when your app is a game you put there all your code. It's not a frobiden or restricted file, neither hell, it's just another file in your project for you to wrtie things inside, just be careful. I believe that DPR means Delphi PRoject/PRogram.
ReplyDeleteAs Kevin says, the Delphi IDE does put some things in the DPR source file - for example, in a VCL application:
ReplyDeleteApplication.MainFormOnTaskbar := True;
Application.CreateForm(TForm15, Form15);
Application.CreateForm(TForm16, Form16);
At the same time, I see no issue with adding more setup and teardown code in the main program - after all, the IDE let's you do "view source" from the Project Manager window :)
But, to quote from Spiderman - "With great power, comes great responsibility"!
I would keep things simple as far as possible with regards to the dpr.
ReplyDeleteYou can achieve what you want with this:
unit Unit1;
interface
var
MyObject : TObject;
implementation
initialization
MyObject := TObject.Create;
finalization
MyObject.Free;
end.
and then when Unit1 is listed in the dpr, MyObject is accessible within the dpr (if needed).
The life cycle of that object is such that it's created and destroyed neatly spanning the running of the Application object.
It's not identical to what happens by adding the code into the dpr, but it's a lot cleaner IMHO.
I am not sure I agree. I rather like the try...finally better to be honest because otherwise you run the risk of having it in the wrong place.
ReplyDeleteI try to avoid messing with the dpr because the IDE is really good at destroying it when you've modified it enough. That said, it's not sacrosanct, and if a change really needs to be there, then that's where it goes.
ReplyDeleteThe other benefit of letting the compiler "take the strain" is that the initialisation and finalisation order are determined by the compiler
ReplyDelete*cough* globals? Well there's your problem right there.
ReplyDeleteHehe he. :) open that can of worms and we have material for another 17 posts. But confession time - I was too lazy to write a getter. Also I didn't know the requirements Olivier had for the object lifetime.
ReplyDeleteHeinz Toskano I let my DataModule manage the splash screen and do all the DB login stuff, if any. In my DPRs, I typically have only two forms - the DM and the Main form. The main form instantiates any necessary child forms programatically, and destroys them when the child form is exited. There are workarounds that make it possible to leave the DPR alone and still accomplish just about anything you would want to do with Delphi. I am not sure why you would code an entire game in the DPR. That sounds like it would be even more trouble than writing separate units.
ReplyDeleteKevin - using a DM is cool. At the same time it might be weird for some developers who might not build database applications. As you mentioned (or was it someone else) - you could have one form that is autocreated that handles a splash screen - and then goes on to create additional forms.
ReplyDeleteI remember visiting several customers who had apps with hundreds of forms (one was a paper form to database offshore data entry company). They had only one auto-create form to put up the log-in for the user, and all of the other forms were created in memory as needed. They had loads of forms - left side was a scanned image of the paper form, right side was a matching Delphi data entry form :)
Kevin McCoy Why do you use units/forms/components? maybe it's for modularity, reusability, organization? Whatever your answer is, is just a coding style or business needs. Not all projects address issues the same way. For example, I use to write many lines of code in DPR, because I need to do some things before the app object starts to run.
ReplyDeleteThe beauty of Pascal is that you can write and organize your code the way you want, you can use units or included files, is up to you. You choose whatever works best for your needs or the needs of your project.
You asked why someone will write a full game directly on the DPR, well you put your main loop there, and use objects, events or classes from as many units you want to have, there are no restrictions.
Did you know that forms can be created by code? Yes you do, is it wrong? maybe yes, maybe not, it will depends on the developer needs.
In the end everything is up to you as developer, quoting SpiderMan again, with great power comes great responsability. Also want to note that it's not my intention to be rude in anyway.
Wow, I did not plan to start a flame war with this post ;) Anyway, I think that the root of the problem was maybe described by Kenneth Cochran : I KNOW that I should not use global objects ...
ReplyDeleteGlobal instances are fine - I don't hear many complaints about this darned Application variable, for example. I would say the first question to ask yourself about that object is "what is that object's lifecycle", and what is the simplest way to define it in code.
ReplyDeleteJust to complete all the possible answers for managing this object, we should consider interfaced objects, where the code defines the lifetime, and then finally the rather old school "let it leak" ;-) - it blows a hole in your memory leak testing, but if the object only directly or indirectly owns in-process resources (e.g. not database rows etc.) it would be fine. Be aware that sometimes the former has become the latter unintentionally ;-)
Hmm, I'll have to disagree with Patrick Martin on his first statement. Despite 50+ years of language research the usefulness of globals is still debated.
ReplyDeleteAnyway, assuming you are using globals I've seen the IDE mangle the dpr often enough to know that you can save yourself a lot of hassle by using the initialization/finalization sections of a normal unit. Version control can undo any damage the IDE may do to the dpr but it's just easier if you don't fight against the IDE. Delphi 2010 and later also support class constructors/destructors, which are invoked before the initialization section and after the finalization, respectively, of the unit where the class is defined.
The order of initialization used at runtime is the order of the units in the uses clause. So the first unit in the dpr will be parsed as well as any units on which it depends, and their dependencies and so-forth and so-on until the compiler runs out of dependencies. Finalizations are the inverse so the first unit initialized will be the last one finalized.
This all takes place before the body of the dpr is run. If you really need your object to be initialized before anything else put it in a unit with no dependencies and make it the first unit listed in the dpr.
Since all initialization sections are guaranteed to run before the program's entry point the only way the order of initialization would make a difference is if an initialization section of one unit is manipulating a global defined in another unit. This is the case for custom memory managers, which overwrite the default memory manager defined in system.pas. This situation is best avoided if you can.