|Perl: the Markov chain saw|
Never lock $0 inside of a BEGIN blockby demerphq (Chancellor)
|on May 21, 2003 at 18:37 UTC||Need Help??|
Hi. This is just a heads up for all you all out there who occasionally use the trick of locking $0 to ensure the script can only have one running instance at a time.
Don't do it in a BEGIN block. The errors that result are downright strange, and give zero indication of the cause of the error. (I managed to track this down just seconds before I was going to submit a very long and frustrated SOPW asking for help :-) At the top of a script I put the following
I guess putting it in a BEGIN block was overly clever (as in the kind of clever that isnt. :-) but it made sense to me at the time, especially when the script appeared to run just fine. HA! I added some extra code and then proceeded to get the weiredst set of errors i have ever seen (missing " at EOF, about 100 lines too early, and all kinds of things like that.) All of the errors seemed to indicate that perl thought the script ended much earlier than it did. So I went nuts trying to find the missing } or ] or " I commented stuff out, I added stuff, etc etc. Nothing worked. But as soon as I removed a particular subroutine the script went back to working. Naturally I thought that the sub is at fault. Well, wrong. If instead I removed the sub before it instead the script would compile fine. (The two subs are about the same size.)
Maybe for the reader what happened and where I am going with this node is clear, however for me the results seemed to be random, and without any logical justification. Until as I was preparing the script for the SOPW I thought to myself, "I wonder if that lock is causing the problem." I changed the BEGIN to an INIT, and presto the weirdness went away (thank the powers that be!)
So what gives? Well, I think what happened is that perl read a certain amount of the program into memory, parsed it and since it contained a BEGIN executed the BEGIN immediately, this then aquired a LOCK_EX on the script, which prevented perl from making any further reads against it (this probably wouldnt be a problem under *nix but im not certain). This of course resulted in perl saying the file EOF'ed at whatever line just happened to be at the end of its buffer. The reason the error went away when I remvoed the sub was that it removed enough bytes to get the entire script in the buffer, and thus compiled and locked itself just fine. By changing the BEGIN to an INIT the lock occured after the whole script had been read and compiled and thus has no problems.
Sigh. Two or three hours wasted over something like this. (/me shakes head) Hopefully this warning will prevent anyone else from encountering this nasty little issue and going throught he same frustration as me.
Update:The following is a lot stronger than I would have said on a nice sunny afternoon. I stand by the sentiment tho. On a bit of a grumble side, IMO one of Perls biggest weaknesses is its absolutely terrible error reporting. The messages are usually misleading and often just plain old wrong. This example here would have been much easier to figure out if it showed the last line, or the line where the quote began. As it was, it was made more difficult because I like most perl programmers have become so used to seeing certain messages and knowing that they in fact indicate a totally different problem to the one being reported that I didnt pay as much attention to the details of what I was being told, especially as it directly contradicted what I could see in a text editor. If you want Kudos in the perl comunity find the tuits to _greatly_ enhance perls miserable error messages. You will be a hero overnight. BTW, if you flame me on this one be prepared for me to respond with numerous examples where perl says one thing and the truth is completely different. :-)
<Elian> And I do take a kind of perverse pleasure in having an OO assembly language...