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.

Comments

  1. yes it is the usual way, but use try-finally statement
    all 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

    ReplyDelete
  2. OK Thanks .
    So 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.

    ReplyDelete
  3. That's because the DPR isn't a unit :)

    Regards,

    A

    ReplyDelete
  4. Andrea Raimondi My dog doesn't bark because it's not a dog.  Sounds logical :)

    ReplyDelete
  5. What I meant is, it's not a unit, it's a program file.
    I 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

    ReplyDelete
  6. 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 .... ;)

    ReplyDelete
  7. Olivier SCHWAB Read with care -- the dpr file is not a unit. It begins with the word program, not unit. It is a meaningful distinction.  ;)

    ReplyDelete
  8. Olivier SCHWAB Please note that I said "The DPR" without specifying Unit just because, well, it is not a unit :)

    ReplyDelete
  9. Bill Meyer In fact, in my 1 year experience in Delphi, I never considered really this file which is auto-generated ....

    ReplyDelete
  10. Olivier SCHWAB One year? I tend to consider everybody "old school" because, well, most of us come from years and years of using Delphi.

    If 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

    ReplyDelete
  11. 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 !

    ReplyDelete
  12. I 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.

    ReplyDelete
  13. Kevin 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.

    ReplyDelete
  14. As Kevin says, the Delphi IDE does put some things in the DPR source file - for example, in a VCL application:
      Application.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"!

    ReplyDelete
  15. I would keep things simple as far as possible with regards to the dpr.

    You 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.

    ReplyDelete
  16. 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.

    ReplyDelete
  17. I 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.

    ReplyDelete
  18. The other benefit of letting the compiler "take the strain" is that the initialisation and finalisation order are determined by the compiler

    ReplyDelete
  19. *cough* globals? Well there's your problem right there.

    ReplyDelete
  20. Hehe 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.

    ReplyDelete
  21. Heinz 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.

    ReplyDelete
  22. Kevin - 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.

    I 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 :)

    ReplyDelete
  23. 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.

    The 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.

    ReplyDelete
  24. 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 ...

    ReplyDelete
  25. Global 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.
    Just 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 ;-)

    ReplyDelete
  26. 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.

     Anyway, 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.

    ReplyDelete

Post a Comment