
japhy
Enthusiast
Sep 8, 2000, 6:24 AM
Post #8 of 15
(6301 views)
|
Hmm, I might end up writing an article on what I'm about to explain. It's about programming more intelligently, more or less. Take a simple function: <BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR> # DOW($N) -- returns day of week for numerical week day (0 - 6) sub DOW { my @days = qw( Sunday Monday Tuesday Wednesday Thursday Friday Saturday ); return $days[shift]; } </pre><HR></BLOCKQUOTE> That's all well and good. It does what I ask of it -- returns the string for the day of the week. But let's look at something a bit more involving: <BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR> sub getDate { my @months = qw( January February March April May June July August September October November December ); my @days = qw( Sunday Monday Tuesday Wednesday Thursday Friday Saturday ); # get abbreviated names... my @smon = map substr($_,0,3), @months; my @sday = map substr($_,0,3), @days; my ($mode,$time) = @_; $mode = 'l' if not $mode; # default to long format # get date information # default to current time my ($sec,$min,$hour,$day,$mon,$year,$wday) = localtime(defined $time ? $time : time); # short date if (lc($mode) eq 's') { return sprintf "%s, %s %d, %d", $sday[$wday], $smon[$mon], $day, $year+1900; } # long date (good kisser?) (that was a joke) if (lc($mode) eq 'l') { return sprintf "%s, %s %d, %d, at %02d 02d 02d", $days[$wday], $months[$mon], $day, $year + 1900, $hr, $min, $sec; } die "bad mode ($mode), expected 's' or 'l'"; } </pre><HR></BLOCKQUOTE> By the way, those angry icons (WHICH I WISH I COULD SHUT OFF) are a colon followed by a percent sign. Now, let's say I have to call this 10,000 times. Here's a benchmark: timethis 10000: 15 wallclock secs (15.49 usr + 0.00 sys = 15.49 CPU) Now, I'm going to make a magical adjustment to this function... done. Now let's check the running time: timethis 10000: 3 wallclock secs ( 4.51 usr + 0.00 sys = 4.51 CPU) WOW! What could I possibly have done to get nearly a 350% speed increase? I only declared the @months, @days, @smon, and @sday arrays ONCE. They won't ever CHANGE, will they? Of course not, so why declare them EVERY time the function gets called? But how did I do that? I didn't create global variables (since that would interfere if I wanted another array called @days later). I didn't make my() variables in the main program, pretty much for the same reason. But I didn't make my() variables IN the subroutine either. I declared them in a block, and defined the subroutine in that block: <BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR> { my $x = 1; sub next_x { return $x++ } } </pre><HR></BLOCKQUOTE> The next_x() function is the ONLY function that can see that $x variable, and the ONLY function that can modify it. So I intelligently rewrote my function as: <BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR> { my @months = qw( January February March April May June July August September October November December ); my @days = qw( Sunday Monday Tuesday Wednesday Thursday Friday Saturday ); # get abbreviated names... my @smon = map substr($_,0,3), @months; my @sday = map substr($_,0,3), @days; sub getDate { my ($mode,$time) = @_; # rest of function.... } } </pre><HR></BLOCKQUOTE> Defining those arrays over and over again was a silly thing to do, so I fixed that. Oh, and there might be VERY little need to use this getDate() function anyway. Calling localtime() in scalar context returns a highly usable string-formatted date. Look into it. <BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR> $date = localtime; # or localtime $seconds; </pre><HR></BLOCKQUOTE> ------------------ Jeff "japhy" Pinyan -- accomplished author, consultant, hacker, and teacher [This message has been edited by japhy (edited 09-08-2000).]
|