Re: Go to perl::critic (updated)
by haukex (Archbishop) on Oct 06, 2019 at 17:26 UTC
|
Is there such a policy?
Here's one :-)
package Perl::Critic::Policy::ControlStructures::ProhibitGotoLabel;
use warnings;
use strict;
use base 'Perl::Critic::Policy';
use Perl::Critic::Utils qw/:severities/;
# to locate the path where to place this file, do e.g.:
# $ perl -MFile::Basename=dirname -MPerl::Critic::Policy::ControlStruc
+tures::ProhibitUnreachableCode -le 'print dirname $INC{"Perl/Critic/P
+olicy/ControlStructures/ProhibitUnreachableCode.pm"}'
# or
# $ dirname `perldoc -l Perl::Critic::Policy::ControlStructures::Prohi
+bitUnreachableCode`
our $VERSION = '0.001';
sub supported_parameters { return }
sub default_severity { return $SEVERITY_MEDIUM }
sub default_themes { return qw/core bugs/ }
sub applies_to { return 'PPI::Token::Word' }
=head1 DESCRIPTION
A C<goto LABEL> is considered a bad practice by a number of people,
as it can lead to hard-to-understand and brittle spaghetti code.
Instead of a C<goto>, use different control structures, or place a
label on a block (such as a loop's block) and use C<next LABEL>,
C<last LABEL>, or C<redo LABEL> instead.
C<goto &NAME> is very different from C<goto LABEL> and is not covered
by this policy. C<goto EXPR> is ambiguous and this policy will report
such cases when C<EXPR> does not begin with C<&>. Whether this is a
false positive or not cannot be determined by a static parse.
=cut
my $DESC = q{goto LABEL used};
my $EXPL = q{Considered bad practice};
sub violates {
my ($self, $elem) = @_;
return if $elem->content() ne 'goto';
my $target = $elem->snext_sibling();
return $self->violation('Nothing following "goto"?',
'It seems there is a lone "goto" in your code?',
$elem) if !$target;
return if $target->isa('PPI::Token::Symbol') && $target->raw_type
+eq '&'
|| $target->isa('PPI::Token::Cast') && $target->content
+eq '&'
|| $target->isa('PPI::Token::Word') && $target->content
+eq '__SUB__';
return $self->violation($DESC,$EXPL,$elem);
}
1;
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
INPUT: print 'number> ';
chomp(my $input = <STDIN>);
if ($input and $input =~ /[0-9]+/) {
print $input, "\n"
}
else {
goto INPUT
}
| [reply] [Watch: Dir/Any] [d/l] |
|
my $input;
INPUT: {
print 'number> ';
chomp($input = <STDIN>);
redo INPUT unless $input && $input=~/\A[0-9]+\z/;
}
print $input, "\n";
(Or just use a proper prompting module, such as IO::Prompter.)
TIMTOWTDI - I'm not saying that goto isn't sometimes an acceptable solution. But IMHO those cases are much more rare than an actual need for goto, especially in a language like Perl that has many other nice options for flow control. And of course if you want to use goto, all Perl::Critic policies are optional; this one just happens to be what the OP wanted. I'm not going to start a debate about whether goto is good or not. Note my wording: "A goto LABEL is considered a bad practice by a number of people, as it can lead to hard-to-understand and brittle spaghetti code." There was a good line by a comedian, paraphrasing: "I love the phrase 'a number of' because it can mean anything. 'A number of supermodels want to sleep with me.' That number is zero."
Update: Fixed the regex. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
|
| [reply] [Watch: Dir/Any] |
|
|
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
Re: Go to perl::critic
by rjt (Curate) on Oct 06, 2019 at 07:45 UTC
|
No such policy. Well, just an orthogonal one that marks code as reachable if it has a label.
My counter-question to you is, what's so bad about goto? Food scientists trying to come up with gluten-free spaghetti have no idea computer science had it covered decades ago. Plus it's great for extra artistic renditions of Queen songs that remind me of how much my programming style has changed since Freddie was filling stadiums:
pts/2 ryan@pi:~/src/shorts $> cat goto.pl
#!/usr/bin/env perl
use 5.010;
use strict;
say 'Thunderbolt and lightning, very, very frightening me';
# say 'Galileo' for 1..5 has nothing on this:
my $galileos = 5;
galileo: say "Galileo";
goto galileo if --$galileos;
figaro: say 'Figaro magnifico';
pts/2 ryan@pi:~/src/shorts $> perlcritic goto.pl
goto.pl source OK
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] [d/l] |
Re: Go to perl::critic
by Anonymous Monk on Oct 06, 2019 at 09:35 UTC
|
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
haukex was awake :) anything to add?
#!/usr/bin/perl --
use strict;
use warnings;
use diagnostics;
sub GOOD {
LINE: while(<STDIN>){
next LINE;
last LINE;
}
}
sub GOOOD {
goto &GOOD;
}
sub GOOOOD {
my $GOOD = 'GOOD';
goto &$GOOD;
}
sub REALLY {
goto &GOOD;
}
sub GOODREALLY {
goto sub { goto &REALLY; };
}
sub GOODREHEALLY {
my $GOO = sub { goto &REALLY; };
goto $GOO;
}
sub GOODREHEHEALLY {
goto do { sub { goto &REALLY; }; };
}
sub BAD {
goto LINE;
}
sub BAAD {
my $LINE = 'LINE';
goto $LINE;
}
sub BAAAD {
goto ("LINE", "LINE", "LINE")[@_];
}
BAAAAD: {
goto &REALLy; # Can't goto subroutine outside a subroutine
}
goto END; ## bad
:END
exit( 0 );
| [reply] [Watch: Dir/Any] [d/l] |
|