2.5. Keys and Indices
When accessing elements of nested data structures (hashes of hashes of arrays of whatever), it's easy to produce a long, complex, and visually dense expression, such as:
$candidates[$i] = $incumbent{$candidates[$i]{get_region( )}};
That's
Unless an index is a simple constant or scalar variable, it's much clearer to put spaces between the indexing expression and its surrounding brackets:
$candidates[$i] = $incumbent{ $candidates[$i]{ get_region( ) } };
Note that the determining factors here are both the complexity and the overall length of the index. Occasionally, "spacing-out" an index makes sense even if that index is just a single constant or scalar. For example, if that simple index is unusually long, it's better written as:
print $incumbent{ $largest_gerrymandered_constituency };
rather than:
print $incumbent{$largest_gerrymandered_constituency};
|
2.6. Operators
Long expressions can be hard enough to comprehend without adding to their complexity by jamming their various
my $displacement=$initial_velocity*$time+0.5*$acceleration*$time**2;
my $price=$coupon_paid*$exp_rate+(($face_val+$coupon_val)*$exp_rate**2);
Give your binary operators room to breathe, even if it requires an extra line to do so:
my $displacement
= $initial_velocity * $time + 0.5 * $acceleration * $time**2;
my $price
= $coupon_paid * $exp_rate + ($face_val + $coupon_paid) * $exp_rate**2;
Choose the amount of whitespace according to the precedence of the operators, to help the reader's eyes pick out the natural groupings within the expression. For example, you might put additional spaces on either side of the lower-precedence
+
to visually
A single space is always sufficient whenever you're also using parentheses to
my $velocity
= $initial_velocity + ($acceleration * ($time + $delta_time));
my $future_price
= $current_price * exp($rate - $dividend_rate_on_index) * ($delivery - $now);
Symbolic unary operators should always be kept with their operands:
my $spring_force = !$hyperextended ? -$spring_constant * $extension : 0;
my $payoff = max(0, -$asset_price_at_maturity + $strike_price);
Named unary operators should be treated like builtins, and
my $tan_theta = sin $theta / cos $theta;
my $forward_differential_1_year = $delivery_price * exp -$interest_rate;
|
2.7. Semicolons
In Perl, semicolons are statement separators, not statement terminators, so a semicolon isn't required after the very last statement in a block. Put one in anyway, even if there's only one statement in the block:
while (my $line = <>) {
chomp $line;
if ( $line =~ s{\A (\s*) -- (.*)}{#}xms ) {
push @comments, ;
}
print $line;
}
The extra effort to do this is negligible, and that final semicolon confers two very important advantages. It signals to the reader that the
Leaving out the final semicolon usually works fine when the code is first written (i.e., when you're still paying proper attention to the entire piece of code):
while (my $line = <>) {
chomp $line;
if ( $line =~ s{\A (\s*) -- (.*)}{#}xms ) {
push @comments,
}
print $line
}
But, without the semicolons, there's nothing to prevent later additions to the code from
while (my $line = <>) {
chomp $line;
if ( $line =~ s{\A (\s*) -- (.*)}{#}xms ) {
push @comments,
/shift/mix
}
print $line
$src_len += length;
}
The problem is that those two additions don't actually add new statements; they just
while (my $line = <>) {
chomp $line;
if ( $line =~ s{\A (\s*) -- (.*)}{#}xms ) {
push @comments, / shift() / mix( )
}
print $line ($src_len += length);
}
This is a very common mistake, and an understandable one. When extending existing code, you will naturally focus on the new statements you're adding, on the assumption that the existing ones will continue to work correctly. But, without its terminating semicolon, an existing statement may be assimilated into the new one instead. Note that this rule does not apply to the block of a map or grep if that block consists of only a single statement. In that case, it's better to omit the terminator:
my @sqrt_results
= map { sqrt $_ } @results;
because
my @sqrt_results
= map { sqrt $_; } @results;
Note that this exception to the stated rule is not excessively
|