Should I use parenthesis in postfix `if` syntax? - perl

Are there any benefits to use parenthesis in postfix if statement? like:
return 1 if ($self->found());
One of my workmate stick to use parenthesis and It's not common for me. I would appreciate if someone point out differences.
Following is output from perl -MO=Deparse
#!/usr/bin/perl
use strict;
my $found = 1;
print "FOUND\n" if $found;
print "FOUND\n" if ($found);
__END__
test.pl syntax OK
use strict;
my $found = 1;
print "FOUND\n" if $found;
print "FOUND\n" if $found;

Parens are never needed around the condition in the if statement modifier, so consistency and playing-it-safe aren't factors. (Same goes for the other statement modifiers.)
I don't see any advantage to using them. In fact, I find them a bit jarring.
I believe most experienced Perl programmers don't use them, to the point that it's a fair indicator of "newbieness".

It's mainly a matter of style. There's no requirement to use parens around the entire conditional expression and it has no effect on the way the code behaves, so decide for yourself what standard you want to use. Personally, I don't, and my impression is that most Perl programmers don't either, but that could just be selection bias.
I will note, though, that any time I start wanting to use parens within the conditional expression, that's a pretty good sign that it shouldn't be in a postfix clause, so then I put parens around the whole thing and change it to the if (...) {...} form.

If you want to use Perl Best Practices, you should only postfix if for control of flow (break, next, last). When you use postfix if you should probably have easy enough if-statements to not need parenthesis.
For If blocks I think the best practice is to use parenthesis.

I usually use the parentheses because more often than not I guess wrong on how many statements I need to be conditional. Then I have to rewrite the line to become a proper if (condition) { BLOCK }. Having the parentheses already there make this slightly easier.
There's also the mental/readability benefit of having all if statements look the same.

Related

Disable Perl warnings for missing qw outer parentheses

Since upgrading Debian recently I've had Perl whining about not having extra parentheses around the qw operator.
As a Systems Administrator this is unacceptable. It is breaking mod_perl applications left, right, and centre.
How can I run Perl with this warning disabled? Is there a flag I can run with the Perl interpreter? Note that editing source is not an option.
This changed in Perl 5.14 - see perldelta.
Use of qw(...) as parentheses
Historically the parser fooled itself into thinking that qw(...)
literals were always enclosed in parentheses, and as a result you
could sometimes omit parentheses around them:
for $x qw(a b c) { ... }
The parser no longer lies to itself in this way. Wrap the list literal
in parentheses like this:
for $x (qw(a b c)) { ... }
This is being deprecated because the parentheses in for $i (1,2,3) {
... } are not part of expression syntax. They are part of the
statement syntax, with the for statement wanting literal parentheses.
The synthetic parentheses that a qw expression acquired were only
intended to be treated as part of expression syntax.
Looks like you can turn the warnings off with no warnings 'qw' but you'd be far better off fixing the code.
As a system administrator I find bad code unacceptable.
The best answer, of course, is to fix the offending perl scripts.
If your business won't let you fix the offending perl scripts, then don't upgrade Debian.
You have risks either way.

Perl does not complain about missing semicolon

I just found on my Ubuntu that Perl is not complaining about the semicolon at the end. Check the following code:
#!/usr/bin/perl
use warnings;
use strict;
my #array = (1, 2, 3, 4);
foreach (#array)
{
print $_."\n"
}
print "no, this cant be true"
Please notice that semicolon ";" is missing from the print statement. Still the code runs fine.
OUTPUT:
1
2
3
4
no, this cant be true
If I put semicolon after print, it still works. So this is confusing to me.
Could you help me understand what am I missing here, OR is there some obvious Perl ideology that I overlooked?
From perldoc perlsyn:
Every simple statement must be terminated with a semicolon, unless it is the final statement in a block, in which case the semicolon is optional.
Your print statement is the last statement in a block.
Omitting the semi-colon isn't recommended though. It's too easy to forget to add it if you extend the block later.
I often think of semicolons in Perl as separators rather than terminators - that makes this behaviour a lot easier to get used to.
That said, it's not at all a bad idea to always use a semicolon as you don't have to remember to add it later if you put more statements at the end of the block, a bit like using an extra comma in a list so that you don't forget to add that later (Perl ignores the last comma if there's no list item after it).
From the Perl documentation:
Every simple statement must be terminated with a semicolon, unless it
is the final statement in a block, in which case the semicolon is
optional.

Evaluating escape sequences in perl

I'm reading strings from a file. Those strings contain escape sequences which I would like to have evaluated before processing them further. So I do:
$t = eval("\"$t\"");
which works fine. But I'm having doubt about the performance. If eval is forking a perl process each time, it will be a performance killer. Another way I considered to do the job were regex, where I have found related questions in SO.
My question: is there a better, more efficient way to do it?
EDIT: before calling eval in my example $t is containing \064\065\x20a\n. It is evaluated to 45 a<LF>.
It's not quite clear what the strings in the file look like and what you do to them before passing off to eval. There's something missing in the explanation.
If you simply want to undo C-style escaping (as also used in Perl), use Encode::Escape:
use Encode qw(decode);
use Encode::Escape qw();
my $string_with_unescaped_literals = decode 'ascii-escape', $string_with_escaped_literals;
If you have placeholders in the file which look like Perl variables that you want to fill with values, then you are abusing eval as a poor man's templating engine. Use a real one that does not have the dangerous side effect of running arbitrary code.
$string =~ s/\\([rnt'"\\])/"qq|\\$1|"/gee
string eval can solve the problem too, but it brings up a host of security and maintenance issues, like # in string
oh gah don't use eval for this, thats dangerous if someone provides it with input like "system('sync;reboot');"..
But, you could do something like this:
#!/usr/bin/perl
$string = 'foo\"ba\\\'r';
printf("%s\n", $string);
$string =~ s/\\([\"\'])/$1/g;
printf("%s\n", $string);

The good, the bad, and the ugly of lexical $_ in Perl 5.10+

Starting in Perl 5.10, it is now possible to lexically scope the context variable $_, either explicitly as my $_; or in a given / when construct.
Has anyone found good uses of the lexical $_? Does it make any constructs simpler / safer / faster?
What about situations that it makes more complicated? Has the lexical $_ introduced any bugs into your code? (since control structures that write to $_ will use the lexical version if it is in scope, this can change the behavior of the code if it contains any subroutine calls (due to loss of dynamic scope))
In the end, I'd like to construct a list that clarifies when to use $_ as a lexical, as a global, or when it doesn't matter at all.
NB: as of perl5-5.24 these experimental features are no longer part of perl.
IMO, one great thing to come out of lexical $_ is the new _ prototype symbol.
This allows you to specify a subroutine so that it will take one scalar or if none is provided it will grab $_.
So instead of writing:
sub foo {
my $arg = #_ ? shift : $_;
# Do stuff with $_
}
I can write:
sub foo(_) {
my $arg = shift;
# Do stuff with $_ or first arg.
}
Not a big change, but it's just that much simpler when I want that behavior. Boilerplate removal is a good thing.
Of course, this has the knock on effect of changing the prototypes of several builtins (eg chr), which may break some code.
Overall, I welcome lexical $_. It gives me a tool I can use to limit accidental data munging and bizarre interactions between functions. If I decide to use $_ in the body of a function, by lexicalizing it, I can be sure that whatever code I call, $_ won't be modified in calling code.
Dynamic scope is interesting, but for the most part I want lexical scoping. Add to this the complications around $_. I've heard dire warnings about the inadvisability of simply doing local $_;--that it is best to use for ( $foo ) { } instead. Lexicalized $_ gives me what I want 99 times out of 100 when I have localized $_ by whatever means. Lexical $_ makes a great convenience and readability feature more robust.
The bulk of my work has had to work with perl 5.8, so I haven't had the joy of playing with lexical $_ in larger projects. However, it feels like this will go a long way to make the use of $_ safer, which is a good thing.
I once found an issue (bug would be way too strong of a word) that came up when I was playing around with the Inline module. This simple script:
use strict qw(vars subs);
for ('function') {
$_->();
}
sub function {
require Inline;
Inline->bind(C => <<'__CODE__');
void foo()
{
}
__CODE__
}
fails with a Modification of a read-only value attempted at /usr/lib/perl5/site_perl/5.10/Inline/C.pm line 380. error message. Deep in the internals of the Inline module is a subroutine that wanted to modify $_, leading to the error message above.
Using
for my $_ ('function') { ...
or otherwise declaring my $_ is a viable workaround to this issue.
(The Inline module was patched to fix this particular issue).
[ Rationale: A short additional answer with a quick summary for perl newcomers that may be passing by. When searching for "perl lexical topic" one can end up here.]
By now (2015) I suppose it is common knowledge that the introduction of lexical topic (my $_ and some related features) led to some difficult to detect at the outset unintended behaviors and so was marked as experimental and then entered into a deprecation stage.
Partial summary of #RT119315:
One suggestion was for something like use feature 'lextopic'; to make use of a new
lexical topic variable:
$^_.
Another point made was that an "implicit name for the topicalizing operator ... other than $_" would work best when combined with explicitly lexical functions (e.g. lexical map or lmap). Whether these approaches would somehow make it possible to salvage given/when is not clear. In the afterlife of the experimental and depreciation phases perhaps something may end up living on in the river of CPAN.
Haven't had any problems here, although I tend to follow somewhat of a "Don't ask, don't tell" policy when it comes to Perls magic. I.e. the routines are not usually expected to rely on their peers screwing with non lexical data as a side effect, nor letting them.
I've tested code against various 5.8 and 5.10 versions of perl, while using a 5.6 describing Camel for occasional reference. Haven't had any problems. Most of my stuff was originally done for perl 5.8.8.

Why won't Perl let me chain a postfix loop from a postfix comparison?

This is ok:
$foo++ if $condition;
And this is ok:
$foo++ for (1..10);
But this isn't:
$foo++ if $condition for (1..10);
I find the latter quite readable if things aren't complicated, and it fits on one line! Is there a way to do this or should I move on with my life?
You can only have one postfix operation per statement. But you can do what you want (sorta) by using a do block, e.g.
do { $foo++ if $condition } for ( 1..10 );
Personally, I find this style extremely confusing and difficult to read. I'd avoid it, if I were you. If you're going to all that trouble, you might as well say
for( 1..10 ) { $foo++ if $condition }
IMHO.
Another way to achieve the same effect as an if statement is with and, so you could say
$condition and $foo++ for 1 .. 10;
However, that is not an encouraged practice.
As I understand it, this was an intentional design decision in the very early days of perl to avoid having people write hard to read or hard to get right code. Perl 6 will allow at least some combinations (if/for and for/if, but not for/for or if/if maybe?) and I believe Perl 5 will follow suit at some point.
Update: Perl 6 will allow a conditional inside a loop (e.g. EXPR if EXPR for LIST ); anything more requires extra parens (e.g. ( EXPR for LIST ) if EXPR ).