Morning | Sun Jun 27 11:50:19 2004 |
| String Lift | |
| Topics: Programming | |
|
My current bathroom book, Programming Perl, has an interesting note in it -- the Perl compiler doesn't hoist initializations out of loops, suggesting that the programmer should exercise some common sense. This is a bad inconsistancy, I think. For you non-programmers, let me demonstrate what hoisting does..
A good C compiler will effectively turn it into this (let's ignore non-hoisting
optimizations):
There are two things to note here, first, length always gets a new value before it is read, so the initializing to zero is unneeded. Further, and this is the main point, there's no need to keep creating and destroying the length variable every time the while block is run through again, so it can do it once outside the block instead. At least as of the writing of that Perl book, Perl will not do this optimization for you. There are no doubt all sorts of other optimizations that Perl does for you, but not that, because they want people to make obvious optimizations themselves. This is important -- it is a good thing to suggest to programmers that they make high-level optimizations, but generally these are of the kind that a compiler cannot (or at least would be difficult to) make for you. It would be fascinating to design a programming language where very rich metadata were provided routinely so really intelligent compilers could more easily make optimizations that no compiler of current languages could do safely.. Perl6 will be making some steps towards this with a rich attribute system. Anyhow, the reason that this particular optimization should be made automatically for the user, contrary to Perl design at that time (hey, maybe in Perl 5.8 or later it changed), is another philosophy in programming that I take to a sort of extreme -- avoid globals. Why avoid globals? It's hard to tell when variables change when it could be changed anywhere in the program. Frequently, the globals are not actually used through the entire program anyhow, but some lazy and bad programmers make everything global. I extend the avoiding of globals to .. well, let's call it superscoping. Under this philosophy, even within functions, we try moderately hard to keep the number-of-lines-scope of variables small. If, for example, we're in the middle of a large, complicated function, and enter an area of the code where we're trying to do something complex and need a lot of variables for it that don't belong in the rest of the code, we'll create an unconditioned block to scope those variables. Example:
Instead of
lockid = socket(...) .... // Stage 2: Open myfile = fopen(fname, ...) if(myfile == NULL) { strncpy(errstring, "Failed to open file: "); strncat(errstring, my_geterror()); ... } // Stage 3: Read while(thisline = fgets(thisline, THISLINE_SIZE, myfile)) { if(regex_match(thisline, "^\S*#")) { ... } ... parseline++; } }
A superscoping way to do that would be:
// Stage 1: Acquire
{
int lockid; int lockmgrsocket; lockid = socket(...) .... }
// Stage 2: Open
{
char errstringLINK=""; myfile = fopen(fname, ...) if(myfile == NULL) { strncpy(errstring, "Failed to open file: "); strncat(errstring, my_geterror()); ... }
}
// Stage 3: Read
{
| |