I came across the following Perl subroutine get_billable_pages
while chasing a bug. It takes 12 arguments.
sub get_billable_pages {
my ($dbc,
$bill_pages, $page_count, $cover_page_count,
$domain_det_page, $bill_cover_page, $virtual_page_billing,
$job, $bsj, $xqn,
$direction, $attempt,
) = @_;
my $billable_pages = 0;
if ($virtual_page_billing) {
my @row;
### Below is testing on the existence of the 11th and 12th parameters ###
if ( length($direction) && length($attempt) ) {
$dbc->xdb_execute("
SELECT convert(int, value)
FROM job_attribute_detail_atmp_tbl
WHERE job = $job
AND billing_sub_job = $bsj
AND xqn = $xqn
AND direction = '$direction'
AND attempt = $attempt
AND attribute = 1
");
}
else {
$dbc->xdb_execute("
SELECT convert(int, value)
FROM job_attribute_detail_tbl
WHERE job = $job
AND billing_sub_job = $bsj
AND xqn = $xqn
AND attribute = 1
");
}
$cnt = 0;
...;
But is sometimes called with only 10 arguments
$tmp_det = get_billable_pages(
$dbc2,
$row[6], $row[8], $row[7],
$domain_det_page, $bill_cover_page, $virtual_page_billing,
$job1, $bsj1, $row[3],
);
The function does a check on the 11th and 12th arguments.
What are the 11th and 12th arguments when the function is passed only 10 arguments?
Is it a bug to call the function with only 10 arguments because the 11th and 12th arguments end up being random values?
I am thinking this may be the source of the bug because the 12th argument had a funky value when the program failed.
I did not see another definition of the function which takes only 10 arguments.
The values are copied out of the parameter array @_
to the list of scalar variables.
If the array is shorter than the list, then the excess variables are set to undef
. If the array is longer than the list, then excess array elements are ignored.
Note that the original array @_
is unmodified by the assignment. No values are created or lost, so it remains the definitive source of the actual parameters passed when the subroutine is called.
ikegami suggested that I should provide some Perl code to demonstrate the assignment of arrays to lists of scalars. Here is that Perl code, based mostly on his edit
use strict;
use warnings;
use Data::Dumper;
my $x = 44; # Make sure that we
my $y = 55; # know if they change
my @params = (8); # Make a dummy parameter array with only one value
($x, $y) = @params; # Copy as if this is were a subroutine
print Dumper $x, $y; # Let's see our parameters
print Dumper \@params; # And how the parameter array looks
output
$VAR1 = 8;
$VAR2 = undef;
$VAR1 = [ 8 ];
So both $x
and $y
are modified, but if there are insufficient values in the array then undef
is used instead. It is as if the source array was extended indefinitely with undef
elements.
Now let's look at the logic of the Perl code. undef
evaluates as false for the purposes of conditional tests, but you apply the length
operator like this
if ( length($direction) && length($attempt) ) { ... }
If you have use warnings
in place as you should, Perl would normally produce a Use of uninitialized value
warning. However length
is unusual in that, if you ask for the length of an undef
value (and you are running version 12 or later of Perl 5) it will just return undef
instead of warning you.
Regarding "I did not see another definition of the function which takes only 10 arguments", Perl doesn't have function templates like C++ and Java - it is up to the code in the subroutine to look at what it has been passed and behave accordingly.