in reply to Re: Re: Re: Execution order of END/CHECK vs BEGIN/INIT
in thread Execution order of END/CHECK vs BEGIN/INIT

I guess we aren't likely to reach an agreement on this. If a resturant put my desert on the table first but told me not to eat it until last, I would probably feel much the same as I do about this.

I appreciate, and implied as much, that my contrived example doesn't hold up to scrutiny, but the point I was trying to make does. If it is legitimate for a module to require an END block to achieve its purpose, then it is also legitimate for my program to have a similar requirement. Your own example probably makes my case better than I can improve upon.

I want to write a program that accesses a DB through a module that use class based DB connection, and an END block to free that connection when the program is cleaning up. Once I have performed my processing, I need to exec a follow-on script. To ensure that all the resources my script uses, directly or indirectly, are properly cleaned up, I place the exec in an END block so that everything gets the chance to clean itself up before I do so.

Except that unless I know that one of the modules I am using has an END block that needs to be called before I exec and take the unusual step of placing my END block at the top of my script before useing that module, then my END block will be called before the modules, the exec occurs and the module never gets it's chance to clean up.

And therein lies the fudge. It may be a reasonable compromise given the architecture, but it is hardly the "right" solution IMO. A correct design would be for the module to have a class method that my program could call to cause the class to explicitly request that it frees off all its resources. That way, I as the main script author can chose when things should be freed, and not have to rely upon explicit knowledge of the calling order of a chain of global events to ensure that my program runs correctly. Of course, if every class/module had such an 'Okay, I'm finished with you so do anything you need to do to clean yourself up' call, then I wouldn't need to use an END block in my code to perform the exec, I could just arrange for it to be the last thing that happened in the normal flow having called the appropriate "I'm done with you" routines, and that would be that.

I can see no logic in the idea that a 'module' should be any more (or less) likely to need to have it's END block called later than my END block? What if I have am using two modules that need their END blocks to be called last. Then which ever order I choose to use them is going to be wrong. The fact that I have to know that I have to use whichever module most needs to have its END block called last, FIRST. Is not just counter-intuative, it's just plain wrong.

There was a recent thread about what order people favour for their use statements. The answers ranged from alphabetical, to pragmas followed by utilities followed by classes, except the vars pragma which which always came last. So far, I haven't hit upon any good reasons to favour any one ordering over any other. They generally get added in what is basically chronological order as I find the need for them. The idea that I should have to scour the source code for each module looking for END blocks and then try and decide what order they should be called in and then reverse that to determine the order of my uses, beggars belief.

I strongly suspect that END blocks came into being as a poor man's 'last gasp', fatal exception clean up mechanism and the real answer is that there should be no inter-module ordering dependancies between them. Were this the case, there would be no need to know what order they execute, which would be a wholey good thing. It would also remove the need to reverse the logical ordering of multiple END blocks within any given source file.

The need for this backward ordering arises soley because the one time exception mechanism has been subverted. People have decided that rather providing an explicit call to perform cleanup and a fatal exception cleanup, they don't need to provide the former and require the caller to use it, because the latter will get called anyway...except that sometimes it doesn't.

I wonder if there is any history of when this ordering decision was made and why. I also wonder if it will persist into P6. Personnally I strongly hope that it doesn't but we will probably have to wait for "Apocolypse N of N" for the answer to that, given that the last Apocolypse would seem to be the logical place to consider END blocks.

But then again, maybe they should have been in Apo 1:)


Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


  • Comment on Re: Re: Re: Re: Execution order of END/CHECK vs BEGIN/INIT

Replies are listed 'Best First'.
Re: Re: Re: Re: Re: Execution order of END/CHECK vs BEGIN/INIT
by tilly (Archbishop) on Jun 28, 2003 at 19:29 UTC
    Question. Have you, in any real code that you have written (as opposed to hypothetical code that you might choose to write some day) ever been bitten by this behaviour? Have you seen anyone complaining about problems which they had because of it?

    Me neither. And it has managed to do the right thing when I needed it in some relatively complex cases.

    As for your module loading question, that is a red herring. Why should it matter what order you use the modules in? If the modules have dependencies, they are responsible for pulling them in, and in so doing will guarantee that any functionality the module needs to have when it unloads will still be there. OK, so this system can get into trouble with circular dependencies (for instance Carp and Exporter have to play games because each depends on the other), but that is at load, not unload. It is not your responsibility to manage your modules' dependencies, and it turns out that you don't need to.

    And now because I pointed out how to create a problem (with exec) you raise that case. Well it is valid, if you wish to use exec you can quickly cause a headache. Use exec in a complex C or C++ program and you cause similar ones for the same reason. (Using it within a Perl script is arguably just using it in a complex C program...) But it seems that most people who want to use exec manage to deal.

    Now suppose that someone comes up with some reason why their module should have its END go last. I have never seen that module, but I can dream up cases where you would want to. Well were I writing that module, I would document that fact up front because it is an important usage note that people are going to have to work with.

    Now suppose that someone else came up with another that did the same. And you wanted to use both. Um, well, good luck. Odds are that if they both want control of the end slot, they do things that are pretty incompatible. If you want both things to happen you probably need to make two system calls (or fork and then load each separately, or something else crazy). Perl cannot anticipate every possible need all of the time. And should not worry itself overly about anticipating needs that people can dream up, but nobody has apparently ever wanted in real life.

    But if you really want to get more control over END blocks, odds are pretty good that you could go stare at Perl's source and find where the END blocks actually get stored for use in cleanup. You can write a module that can go and manipulate those internals to your heart's content. It would actually be useful if you used it to implement versions of exit and exec that actually call the END blocks before exiting.

    However I don't think that you will find that anyone is particularly unhappy with how END blocks work in practice. (You might find some unhappiness with exit and exec though. But not that much since most people have found their own ways around that possible breakage.)

    And finally, given that END blocks don't cause significant complaint now, and the person who was in charge then is still in charge, well guess what I predict Larry Wall is going to say in the appropriate Apocalypse?

      Sorry, but your still missing (what I think) is the point.

      Why should it matter what order you use the modules in?

      And that's my point. It shouldn't. But if it didn't, then perl wouldn't go to the bother of inverting the natural order of their execution.

      If the order of the modules (specifically those that have END blocks) doesn't matter, then why does Perl bother to impose this peculiar ordering of execution?

      The reason offered elsewhere in this thread is it is necessary to have DB modules execute their END blocks after their callers END blocks, so that the caller had a chance to save their datasets, prior to the DB module dropping its connection. I assumed that you had read this too.

      I'll shut up now as requested.


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller