[sf-perl] Trying to understand 'caller'
David Christensen
dpchrist at holgerdanske.com
Mon Mar 16 14:32:59 PDT 2020
sfpm:
I am working on a function for generating debugging information and am
trying to understand the behavior of 'caller'. Please see my test
script 'caller-20200316.t' and the console sessions, at the bottom.
The first through third, and fifth through seventh, test cases behave as
I expect, but the fourth test case surprises me:
1. The test case is defined on line 24.
2. The value to be tested is the return value of uut().
3. I expected uut() to return a value of 24, but uut() returns 27.
The first line of output holds a clue:
# uut $u = 27;
I believe this output was produced when Perl evaluated the definition of
@case (lines 20-30); and, specifically, when Perl evaluated the call to
uut() in the second position of the fourth test case.
My guess is that when 'caller' is invoked in a function and that
function is invoked in a multi-line statement, the line number returned
by 'caller' is the line number of the last expression evaluated in the
multi-line statement (?). And, blank lines and comments are ignored (?).
Comments?
David
### First console session, Debian GNU/Linux:
2020-03-16 14:09:09 dpchrist at tinkywinky ~/sandbox/perl
$ cat /etc/debian_version ; uname -a ; perl -v | head -n 3
9.12
Linux tinkywinky 4.9.0-12-amd64 #1 SMP Debian 4.9.210-1 (2020-01-20)
x86_64 GNU/Linux
This is perl 5, version 24, subversion 1 (v5.24.1) built for
x86_64-linux-gnu-thread-multi
(with 86 registered patches, see perl -V for more detail)
2020-03-16 14:09:34 dpchrist at tinkywinky ~/sandbox/perl
$ cat caller-20200316.t
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use Test::More;
$| = 1;
$Data::Dumper::Indent = 0;
sub _d { join $", Data::Dumper->Dump(@_) }
sub uut {
my $u = (caller)[2];
note 'uut ' . _d [$u], [qw(u)];
return $u;
}
my @case = (
[__LINE__, __LINE__, __LINE__ ],
[__LINE__, sub { __LINE__ }, __LINE__ ],
[__LINE__, sub { (caller)[2] }, 0 ],
[__LINE__, uut(), __LINE__ ], # 27?
[__LINE__, \&uut, 0 ],
[__LINE__, sub { uut() }, __LINE__ ],
[__LINE__, sub { \&uut }, 0 ],
# Third column of 0 means call to 'caller' is delayed and test loop
# must compute expected value.
);
for my $case (@case) {
my ($l, $v, $x) = @$case;
note 'for ' . _d [$l, $v, $x], [qw(l v x)];
while (ref $v) {
$v = $v->();
$x = __LINE__ - 1 unless $x;
note 'while ' . _d [$v, $x], [qw(v x)];
};
is $v, $x, 'is ' . _d [$v, $x], [qw(v x)];
}
done_testing;
2020-03-16 14:09:39 dpchrist at tinkywinky ~/sandbox/perl
$ perl caller-20200316.t
# uut $u = 27;
# for $l = '21'; $v = '21'; $x = '21';
ok 1 - is $v = '21'; $x = '21';
# for $l = '22'; $v = sub { "DUMMY" }; $x = '22';
# while $v = '22'; $x = '22';
ok 2 - is $v = '22'; $x = '22';
# for $l = '23'; $v = sub { "DUMMY" }; $x = 0;
# while $v = 37; $x = 37;
ok 3 - is $v = 37; $x = 37;
# for $l = '24'; $v = 27; $x = '24';
not ok 4 - is $v = 27; $x = '24';
# Failed test 'is $v = 27; $x = '24';'
# at caller-20200316.t line 41.
# got: '27'
# expected: '24'
# for $l = '25'; $v = sub { "DUMMY" }; $x = 0;
# uut $u = 37;
# while $v = 37; $x = 37;
ok 5 - is $v = 37; $x = 37;
# for $l = '26'; $v = sub { "DUMMY" }; $x = '26';
# uut $u = 26;
# while $v = 26; $x = '26';
ok 6 - is $v = 26; $x = '26';
# for $l = '27'; $v = sub { "DUMMY" }; $x = 0;
# while $v = sub { "DUMMY" }; $x = 37;
# uut $u = 37;
# while $v = 37; $x = 37;
ok 7 - is $v = 37; $x = 37;
1..7
# Looks like you failed 1 test of 7.
### Second console session, FreeBSD with newer version of Perl:
2020-03-16 14:12:25 dpchrist at f3 ~/sandbox/perl
$ freebsd-version ; uname -a ; perl -v | head -n 2
12.1-RELEASE-p2
FreeBSD f3.tracy.holgerdanske.com 12.1-RELEASE-p2 FreeBSD
12.1-RELEASE-p2 GENERIC amd64
This is perl 5, version 30, subversion 1 (v5.30.1) built for
amd64-freebsd-thread-multi
2020-03-16 14:12:29 dpchrist at f3 ~/sandbox/perl
$ perl caller-20200316.t
# uut $u = 27;
# for $l = '21'; $v = '21'; $x = '21';
ok 1 - is $v = '21'; $x = '21';
# for $l = '22'; $v = sub { "DUMMY" }; $x = '22';
# while $v = '22'; $x = '22';
ok 2 - is $v = '22'; $x = '22';
# for $l = '23'; $v = sub { "DUMMY" }; $x = 0;
# while $v = 37; $x = 37;
ok 3 - is $v = 37; $x = 37;
# for $l = '24'; $v = 27; $x = '24';
not ok 4 - is $v = 27; $x = '24';
# Failed test 'is $v = 27; $x = '24';'
# at caller-20200316.t line 41.
# got: '27'
# expected: '24'
# for $l = '25'; $v = sub { "DUMMY" }; $x = 0;
# uut $u = 37;
# while $v = 37; $x = 37;
ok 5 - is $v = 37; $x = 37;
# for $l = '26'; $v = sub { "DUMMY" }; $x = '26';
# uut $u = 26;
# while $v = 26; $x = '26';
ok 6 - is $v = 26; $x = '26';
# for $l = '27'; $v = sub { "DUMMY" }; $x = 0;
# while $v = sub { "DUMMY" }; $x = 37;
# uut $u = 37;
# while $v = 37; $x = 37;
ok 7 - is $v = 37; $x = 37;
1..7
# Looks like you failed 1 test of 7.
More information about the SanFrancisco-pm
mailing list