perl-modperl mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ch...@prather.org
Subject Re: Speed of "if,elsif" versus $hash ...
Date Thu, 08 May 2003 09:43:27 GMT
On 8 May 2003 at 10:18, Jim Morrison [Mailing-Lists] wrote:

> I just had a thought.. Maybe it's not a great one, but I'd appreciate
> some guidance..
> 
> I tend to start my scripts with a big if like :
> 
> 	if 	( $method eq 'foo' ){ do_something(); }
> 	elsif ( $method eq 'bar' ){ do_somethingelse();}
> 	etc..
> 
> It's not too uncommon for this to become quite a big if,elsif,elsif ..
> Which is ok I guess cos it's only one and it determines the whole of the
> rest of the operation of the cgi..  .. But I've noticed another 'sub' I
> have that returns path's to files acording to standard rules that is
> also becoming quite big.. It follows the same rules :
> 
> sub path{
> 	my $self = shift;
> 	my $path = shift;
> 	if 	($path = 'www'){ return '/home/' . $self->{domain} .
> '/www/'; }
> 	elsif ($path = 'foo'){ return '/bar/foo/'; }
> 	etc..
> } 
> 
> This might get called quite frequently.. So what I'm wondering is, if I
> were to make a hash :
> 
> 	my %paths = ( www => \sub{ return '/home/' . $self->{domain} .
> '/www/' },
> 			  foo => '/bar/foo',
>                     etc => ....
>                    )

This is not specifically a mod_perl question. Another list might be more suitable in 
the future. However I didn't realize you'd posted this to modperl and not one of the 
other lists so I'm including my original reply.

--------

$paths{www} won't execute the anonymous sub here. It will just return a reference 
to the sub. You'd need something like:

my %paths = ( www => eval { return '/home/' . $self->{domain} . '/www/' }, ...)

In your version to get this same results you'd need to say:

my $path =  &$paths{wwww} 

or some such to get the result out of the anonymous sub.
 
> Then looking up the path would be much quicker right?? Because if it's a
> long if,elsif,elsif then I'd have to itterate through it every time,
> whereas if it's a hash I don't?? (I'm not too sure of the syntax of
> putting the 'sub' in, is that right?)
>
> Anyway - the way I figure it is that any time you've got an if,elsif
> statement that get's called a lot, or is particularly long, you'd be
> much better of predefining it as a hash of references to functions
> because it would resolve much faster.. - have I got this wrong or does
> everyone else know this already? ;-)

I'm not sure how much "everybody knows" is, but I do know that this is called a 
lookup table. And you're right it tends to win over if/then/else in large sets of lookups

because while each access is (possibly) slower, it's constant time ( O(1) ) where as 
if/then/elseif/else is variable ( O(n) ). 
 
> Only other thing that bothers me is, in the first example I can quite
> happily use $self->{domain} to get something out of the $self passed to
> the function.. In the hash example - I'm not sure I understand the scope
> of the 'sub' .. Can I pass it arguments, and how do I get to $self??

As long as $self is defined in the same scope as the subroute the sub has access to 
it. This is called a "closure" over the variable. Take a look at this for an example:

sub make_adder { 
  my $foo = 0;
  return sub { return $foo++ };
}

my $adder1 = make_adder();
my $adder2 = make_adder();

print &$adder1; # prints 0
print &$adder1; # prints 1
print &$adder2; # prints 0
print &$adder1; # prints 2

Look in the Perl docs for things called Closures, and Anonymous subs. Also you 
might want to check out Damnian Conway's OO Perl because it has a nice big 
section on Dispatch Tables (starting wth p358 and bouncing around there).

-Chris

Mime
View raw message