Argel has asked for the wisdom of the Perl Monks concerning the following question:
Example:
if( ! exists $dg_by_id{$group_id} and $group_id != 0) {}
Lately I've been writing scripts for an application with it's own lighter weight scripting language and a Perl API. The proprietrary language uses syntax such as
$model like /pattern/
$IPaddress in [ 192.168.0.0/24, 192.168.1.0/24 ] and $IPaddress not in
+ [ 192.168.0.1/32, 192.168.1.1/32]
, etc. Even in Perl scripts, we have to use some of their language to specify filters (like what to/not to run against) in the proprietary language format in a special comment block at the top. So, lately, even in Perl I've found myself writing 'and' instead of '&&" and ditto for 'or'. I'm not as fast to use 'not' instead of '!', but it's tempting. One benefit is for our non-programming users, they can make more sense of the Perl code.
My question is what's the risk/harm in using them like this? There's the low precedence that allows them to work, but I haven't been bitten by that yet (that I know of).
Re: Thoughts on using and, or, and not over && || !?
by Athanasius (Archbishop) on Jul 12, 2016 at 03:14 UTC
|
Hello Argel,
In addition to the potential predecence problems with or, it should be noted that Perl’s // (Logical Defined-Or) operator has no low-precedence equivalent, so if you get in the habit of using or in place of ||, you may more easily overlook situations in which // is a better fit:
13:09 >perl -Mstrict -wE "my ($y, $z); my $x = (defined $y or defined
+$z or 'default'); say $x;"
default
vs.
13:09 >perl -Mstrict -wE "my ($y, $z); my $x = $y // $z // 'default';
+say $x;"
default
13:09 >
As a rule I use and and or for flow control only:
open(my $fh, '<', $filename) or die "Cannot open file '$filename' for
+reading: $!";
Hope that helps,
| [reply] [d/l] [select] |
|
Good post++. I would just add that the //= version of this operator is also available.
my $xyz;
$xyz //= 'default';
print $xyz; #default
| [reply] [d/l] |
|
open my $fh, '<', $qfn
|| die $!;
with
open my $fh, '<', $qfn
or die $!;
| [reply] [d/l] [select] |
Re: Thoughts on using and, or, and not over && || !?
by choroba (Cardinal) on Jul 11, 2016 at 22:20 UTC
|
return $result or $default
Fortunately, more recent perls would warn you:
Possible precedence issue with control flow operator at ...
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
| [reply] [d/l] [select] |
|
I'm using Perl 5.16.3, so I might get the warnings. Good example of where it could be a problem. Thanks!
| [reply] |
Re: Thoughts on using and, or, and not over && || !? (purpose)
by tye (Sage) on Jul 12, 2016 at 18:24 UTC
|
or was basically created for use in code like open ... or die .... That is why it was given extremely low precedence. It was not implemented as a "pretty" replacement for ||. So, or was meant to be used for flow control between statements while || continues to be meant for use in logical expressions.
Using || for flow control between statements was often leading to bugs:
open FOO, '<', $foo
|| die "Could not read $foo: $!\n";
That is still an easy bug to introduce, so you should use or for such.
So it should be no surprise that you can easily introduce bugs by using or for building logical expressions. In fact, I've seen quite a few bugs from quite a few different highly experienced Perl developers due to the use of or (or and) for building logical expressions.
They didn't even realize that they had introduced the bugs. So, perhaps you are just way better than all of those highly experienced Perl developers I've worked with. Maybe, the people who say "I've never made such mistakes" are actually correct in their assessment despite the multiple examples of people who thought they had not made that mistake until I pointed it out to them.
So I discourage people from using or for what || was designed for and vice-versa.
No bug:
if( $foo->is_ready() and $foo->needs_munging() ) {
$status = $foo->munge();
} else {
$status = $foo->status();
}
Bug easily introduced:
$status = $foo->is_ready() and $foo->needs_munging()
? $foo->munge() : $foo->status();
No warning generated. Lots of different ways to make that same mistake.
Hammers are ungainly and weirdly shaped. Screwdrivers are sleek and cylindrical. I pound nails in with screwdrivers because I think it makes the act of pounding in nails easier on the eyes. Some people think I'm silly for choosing my tools based on style considerations over how the tools were designed to be used. But I've never had problems with the nails I've pounded in, so what do they know?
| [reply] [d/l] [select] |
|
| [reply] |
|
my $do_munge = $foo->is_ready() and $foo->needs_munging();
return $foo->is_ready() and $foo->needs_munging();
$count += $foo->willing() and $foo->able();
push @passes, $foo->tried() and $foo->success();
$separator = $args->{separator} or ',';
skip_if( $not_mocked or $in_prod, sub { test_stuff() } );
LOG "Failure to launch.", because => $!, 'retry?' => $retries_left and
+ $not_fatal;
| [reply] [d/l] |
|
|
|
But couldn't parenthesis be used with the low precedence operators in that example? Sometimes we have to use parenthesis with the high precedence operators (that's why "or" was created for flow control), so how is using them with the low precedence operators any different, beyond what came first/tradition?
| [reply] |
|
The problem with parentheses is you need to know where to put them. See e.g. this infamous Python question (I apologize to the God(s) of Programming for staining the Monastery):
>>> False in [False, True]
True
>>> not (True) in [False, True]
False
>>> (not True) in [False, True]
True
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
| [reply] [d/l] [select] |
|
|
|
Re: Thoughts on using and, or, and not over && || !?
by eyepopslikeamosquito (Archbishop) on Jul 12, 2016 at 20:22 UTC
|
For flow of control, prefer the low precedence
and and or operators.
A common example of preferring or to || is:
open(my $fh, '<', $file) or die "error opening '$file': $!";
That is probably the principal use case as to why the low precedence operators were added to the language in the first place.
Reserve && and || for logical expressions, not flow of control, for example:
if ($x > 5 && $y < 10) ...
This is discussed in detail in Perl Best Practices,
Chapter 4, "Values and Expressions" in the "Don't mix high- and low-precedence booleans" item.
| [reply] [d/l] [select] |
Re: Thoughts on using and, or, and not over && || !?
by Anonymous Monk on Jul 12, 2016 at 08:19 UTC
|
| [reply] |
Re: Thoughts on using and, or, and not over && || !?
by Laurent_R (Canon) on Jul 12, 2016 at 12:42 UTC
|
Both the high and the low precedence logical operators have their own pitfalls, so you have to be careful anyway.
Having said that, I find that the low precedence logical operators express much more often what I want, probably in more than 90% of the cases, so that's what I am using most of the time. Also, since they are so low in the operator precedence list, I most of the time don't need to look up the documentation to find out if I am right.
So, even though I tended to use the high-precedence operators when I picked up Perl, because of my background with C and C-derived languages, I quickly moved to and, or and not.
| [reply] [d/l] [select] |
Re: Thoughts on using and, or, and not over && || !?
by Anonymous Monk on Jul 11, 2016 at 22:24 UTC
|
I do it as often as I can. I think it makes code "more readable".
(I also try to use as few parentheses as possible for the same reason.)
| [reply] |
|
"More readable" is always a judgement call. Redundant parenthesis are a big improvement to the reader that is spared from consulting the precedence tables.
| [reply] |
Re: Thoughts on using and, or, and not over && || !?
by Argel (Prior) on Jul 15, 2016 at 12:47 UTC
|
Thanks for the advice everyone!!
So, looking at the pro-high precedence arguments... What's the difference between using parenthesis for clarity and to address precedence issues with the high precedence operators vs. the low precedence ones? It seems like the answer to that is familiarity with the high precedence operators, the precedence for the high precedence operators, tradition, and of course older versions of Perl that do not have the low precedence operators.
Put differently, if the low precedence operators had existed from the beginning and the high precedence ones were added recently the low/high arguments would be reversed.
So, back to my situation.
- We're using Perl 5.16.3 with the app and it either requires 5.14.x or 5.16.x.
- My users are not programmers and most do not even write scripts. They do copy existing scripts
to tweak them though.
- The other language, which only uses "and", "or", and "not", ...
- is normally used for simpler tasks (but can be used for moderately complicated stuff). Edit: In other words, we will be using both languages.
- is the one our users are more likely to spend time learning (or learn by continued use over time).
- has to be used in Perl scripts to specify the Script-Filter. For example:
# BEGIN-SCRIPT-BLOCK
# Script-Filter:
# $vendor eq "Cisco"
# and $sysdescr like /IOS/
# and $model like /2[89][05]/
# Script-Variables:
# $tftp_server text "192.168.0.2"
# $dest_name text
# $source_name text
# $MD5 text "Enter the MD5 hash for the source file here"
# $reload_cmd text "reload at 00:00 reason New Firmware"
# Script-Timeout: 300
# END-SCRIPT-BLOCK
So, going back to what I wrote at the top. The main argument against the low precedence operators appears to boil down to "tradition" and backwards compatibility. The examples where it can trip someone up can be dealt with by using parenthesis, right? For example, for tye's example:
$status = ( $foo->is_ready() and $foo->needs_munging() ) ? $foo->munge
+() : $foo->status();
Assuming parenthesis can be used to deal with the precedence issues and I am hard pressed to see why they cannot, then I think the other factors in my situation favor using the low precedence operators because it will be more "consistent" across the two scripting languages, which will make life easier for my mostly non-programmer user base. I am not going to claim it's ideal, but my job is to help them do their job.
| [reply] [d/l] [select] |
|
Hi Argel,
In your situation (users are not programmers), I'd say it's easier to teach people to use parentheses everywhere than to teach them the operator precedence table, especially across multiple languages. If you use parens everywhere, it doesn't matter whether you use high- or low-precedence ops.
Hope this helps, -- Hauke D
| [reply] |
|
I'd say it's easier to teach people to use parentheses everywhere than to teach them the operator precedence table
I feel that is going too far. Since = is an operator, that advice requires you to use parens here:
my $x = ( $y + 42 );
Do you do that?
Whether parens "clutter" or "clarify" is a matter of taste. I prefer the middle ground here to the extreme positions of "always use parens" or "memorize the precedence table and never use parens".
| [reply] [d/l] [select] |
|
|
|
| [reply] |
|
|
|