I'm doing some Perl and seeing my nested "if" statements is driving me mad. I managed to reduce some of them with guard blocks in another section, but I'm stuck here.
Do you think I may leave the code as is, or is there a "proper" way to refactor the following ? (I also admit being relatively new to Perl)
This is actually a subroutine asking for user input on each parameters of a list (external file). $[3] is the matching pattern, $[2] is the default value for the considered parameter (NULL if there is none), $_[1] specifies if it is mandatory or not. the 'next' statement refers to the next parameter read (while loop).
With everyone's help (thanks !), here's the newest version.
100 if ( $input ne '' && ( $input !~ $match || $input =~ /'.+'/ ) ) {
101 print "! Format not respected. Match : /$match/ (without \' \')\n";
102 next;
103 }
104 if ( $input eq '' ) {
105 if ( $default eq 'NULL' ) {
106 if ( $manda eq 'y' ) {
107 print "! Mandatory parameter not filled in\n";
108 next;
109 }
110 print "+ Ignoring parameter.\n";
111 $input = '';
112 }
113 else {
114 print "+ Using default value\n";
115 $input = $default;
116 }
117 }
98 if($input eq ''){
99 if($_[2] eq 'NULL'){
100 if($_[1] eq 'y'){
101 print "! Mandatory parameter not filled in\n";
102 next;
103 }
104 else{
105 print "+ Ignoring parameter.\n";
106 $input = '';
107 }
108 }
109 else{
110 print "+ Using default value\n";
111 $input = $_[2];
112 }
113 }
114 elsif($input !~ $_[3] || $input =~ /'.+'/){
115 print "! Format not respected. Match : /$_[3]/ (without \' \')\n";
116 next;
117 }
118 }
In most cases, you'd use an IF formula to test your condition and return one value if the condition is met, another value if the condition is not met. To evaluate more than one condition and return different values depending on the results, you nest multiple IFs inside each other.
A nested if...else statement can perform much faster than a series of single-selection if statements because of the possibility of early exit after one of the conditions is satisfied.
A nested if statement is an if statement placed inside another if statement. Nested if statements are often used when you must test a combination of conditions before deciding on the proper action.
Here's a slightly more readable version of chaos' answer:
# Set sane variable names...
my ($is_required, $default, $pattern) = @_
# Convert the external string convention for simpler evaluation...
$default = undef if $default eq 'NULL'
# Refuse problematic input before going any further...
if ($input ne '' && $input !~ $pattern || $input =~ /'.+'/) {
print "! Format not respected. Match : /$pattern/ (without \' \')\n";
next;
}
# If there was no input string...
if($input eq '') {
# Set the default, if one was provided...
if( $default ) {
print "+ Using default value\n";
$input = $default;
}
# otherwise, complain if a default was required...
else {
if( $is_required eq 'y' ){
print "! Mandatory parameter not filled in\n";
next;
}
print "+ Ignoring parameter (no input or default provided).\n";
}
}
The key points are:
An alternative approach that sometimes helps with readability is to put some or all of the branches in well-named code references. Here is a start on the idea:
$format_not_respected = sub {
return 0 if ...;
print "! Format not respected....";
return 1;
}
$missing_mandatory_param = sub {
return 0 if ...;
print "! Mandatory parameter not filled in\n";
return 1;
}
next if $format_not_respected->();
next if $missing_mandatory_param->();
etc...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With