[svhwan@alpaca ~/prodscript]$ cat beExplicit.html orAndNot.html > trapsPrecedenc Perl Traps - It's annoying to keep track of precedence

DISCLAIMER: THESE PAGES ARE STILL UNDER CONSTRUCTION. NO CODE EXAMPLE BEEN TESTED YET.

Perl Traps

It's annoying to keep track of precedence


[Previous Page] |[Next Page] Table of Contents: small | med | large

I've actually already discussed these examples in my pages about being explicit and Or, And, and Not, but I thought it was important enough to go over again. In fact, I'm just going to do a little cut-and-paste and literally copy those sections...

It's useful to know the order of precedence of Perl operators. You can read the man pages and see a table. But let's say you have an if block that you want to evaluate if one of 3 conditions is satisfied:

We could implement this with:
	if ( $hr < 10 && $ampm eq 'pm' || $name1 eq 'Jennifer' && $name2
			eq 'Love' && $name3 eq 'Hewitt' || $cashBox < 200) {
		&admitGuest();
	}
Okay, maybe this really wasn't a production example. I just felt like using the name "Jennifer Love Hewitt" in an example.

Now, I just think that's a mess. Consult with the precedence tables, and you'll see that it's okay. But I can never remember whether and(&&) or or(||) has precedence, and it's hard for me to group terms together. Since i can never remember precedence, and I know I won't remember precedence rules when I debug the code later (yes, my code will usually have bugs), I prefer to see:

	if ( (($hr < 10) && ($ampm eq 'pm'))
			|| (($name1 eq 'Jennifer') && ($name2 eq 'Love')
						&& ($name3 eq 'Hewitt'))
			|| ($cashBox < 200)) {
		&admitGuest();
	}

In Perl 5 (might be 5.005, I'm not sure...), they introduced some new boolean operators, or, and, not which can be used instead of ||, &&, ! respectively. In an earlier page, I went over the example:

	if ( (($hr < 10) && ($ampm eq 'pm'))
			|| (($name1 eq 'Jennifer') && ($name2 eq 'Love')
						&& ($name3 eq 'Hewitt'))
			|| ($cashBox < 200)) {
		&admitGuest();
	}

Well, these days, I would do this instead:

	if ( (($hr < 10) and ($ampm eq 'pm'))
			or (($name1 eq 'Jennifer') and ($name2 eq 'Love')
						and ($name3 eq 'Hewitt'))
			or ($cashBox < 200)) {
		&admitGuest();
	}

Similarly, if I was trying to set a default value I might do something like this:

	if (! defined($shadingRate)) {
		$shadingRate = 0.25;
	}

but these days, I would say:

	if (not defined($shadingRate)) {
		$shadingRate = 0.25;
	}

So I think it's pretty much a no-brainer that or/and/not is more readable than ||/&&/!. However, there are a few things that you need to be careful about. The main thing is operator precedence. In an earlier page I discussed precedence issues and suggested the over-use of parenthesis () to explicitly declare precedence rather than counting on the implicit precedence inherent to Perl. This is mainly because I can never remember what the precedence tables are.

This can actually come back to bite you in weird ways. The big difference here is that or/and/not are the absolute bottom precedence, so any other operator will tend to want to bind first.

Supposing (real life example) you are editing someone's scene browser and you want to do something to each file satisfying a certain criterion. Suppose, for example, that you want to do something with all files that satisfy:

Now, usually, I don't like to implicitly use the $_ variable, but I was working on someone else's program, and when I do that, I try to emulate the other person's coding style (unless it excessively annoys me). For that matter, I still haven't decided whether or not I like putting the grep inside the iteration array. One way we could code our little test is:
	foreach my $filename (grep /\.tif$/ && (! -l), @fileList) {
		# do something with each filename
	}
So what happens if we blindly change out the && with an and?
	foreach my $filename (grep /\.tif$/ and (not -l), @fileList) {
		# do something with each filename
	}
Well, if you tried to enter that, I believe Perl would actually refuse to compile. It looks pretty mysterious, but here's what is happening: and has such low precedence that (not -l) is binding with the , so that it sees (not -l), @fileList, which evaluates to the scalar version of the second argument, @fileList will evaluate to be the number of elements in @fileList. Then the and comes into play and evaluates /\.tif$/ and scalar(@fileList), which evaluates to a scalar. grep, however, requires at least 2 arguments, but because of the bizarre precedence, we only have 1, so it won't compile.

Of course, this can all be saved with some parenthesis:

	foreach my $filename (grep (/\.tif$/ and (not -l)), @fileList) {
		# do something with each filename
	}

So in summary:


© 2001 Steve Hwan, hostname: @pacbell.net, username: svhwan
You should probably use the word "PERL" in the subject line to get my attention.
Last Modified: Wed Apr 25 22:52:42 2001