Possible bug in caller(0) ?

S

szr

Given the code and output below, I believe there to be a bug in caller,
specifically when called with a sole argument of 0 (zero.) In the output
below, I get back the subroutine (method), B::foo, which is located in
Package "B", inside file Test.pm, at line 10, yet caller(0) is yielding
Package "main", file main.pl, and line 8.

The latter location is where 'foo' was called /from/, but caller(0),
according to `perldoc5.10.0 -f caller`, whose first four elements are
defined as "$package, $filename, $line, $subroutine", states that:

The value of EXPR indicates how many call frames to go back
before the current one.

Therefore 0 should be the current frame, and while the subroutine is
correct, is appears the package, file, and line number (aka, the
location of said subroutine), is incorrect. I would have expected
caller(1) to return where it was called _from_, but caller(0) be giving
the location of the subroutine where caller was called.

If I am missing something, please let me know. I have thought though
this for a couple hours and read over that perldoc entry several times
before writing this.

Thank you.


###### Output #####

$ ./main.pl
[main, ./main.pl, 8, B::foo]
$ # shouldn't this be [B, ./Test.pm, 10, B::foo] ?

###################

##### Test.pm #####
package B;

use strict;

sub new {
my $this = shift;
return bless { }, ref($this) || $this;
}

sub foo {
my $this = shift;
return join (', ', (caller(0))[0..3]);
}


package D;

use strict;
our @ISA = qw(B);

sub new {
my $this = shift;
my $class = ref($this) || $this;
my $obj = $class->SUPER::new(@_);
return bless $obj, $class;
}

1;
###################

##### main.pl #####
#!/usr/bin/perl -w

use strict;
use lib '.';
use Test;

my $d = new D;
print "[", $d->foo(), "]\n";
###################
 
S

sln

Given the code and output below, I believe there to be a bug in caller,
specifically when called with a sole argument of 0 (zero.) In the output
below, I get back the subroutine (method), B::foo, which is located in
Package "B", inside file Test.pm, at line 10, yet caller(0) is yielding
Package "main", file main.pl, and line 8.

The latter location is where 'foo' was called /from/, but caller(0),
according to `perldoc5.10.0 -f caller`, whose first four elements are
defined as "$package, $filename, $line, $subroutine", states that:

The value of EXPR indicates how many call frames to go back
before the current one.

Therefore 0 should be the current frame, and while the subroutine is
correct, is appears the package, file, and line number (aka, the
location of said subroutine), is incorrect. I would have expected
caller(1) to return where it was called _from_, but caller(0) be giving
the location of the subroutine where caller was called.

If I am missing something, please let me know. I have thought though
this for a couple hours and read over that perldoc entry several times
before writing this.

Thank you.
[snip]

Usually call frames tell info obout the caller(s), what was passed, so its mostly about
the call stack or call tree, to trace back the sequence. Its a good debug tool.
Microsoft VS development ide has an excellent one.

($package, $filename, $line, $subroutine) = caller(0); is a stack frame (kinda) of the subroutine caller.

In your case, $d->foo(), the last called before 'caller()' was invoked, was called from the 'main' package,
your filename was 'main.pl', the line in main.pl was 8, and the subroutine called was B::foo.

Take a look at the sample and output below.

The first call to $d->foo() was made at the end of package D. So, you get this: d->foo() = [D, iii.pl, 31, B::foo]
The first call to $e->foo() was made at the end of package E. So, you get this: e->foo() = [E, iii.pl, 52, B::foo]
The second call to $d->foo() was made at the end of package E. So, you get this: d->foo() = [E, iii.pl, 53, B::foo]

Then "$e->bar()" was called. E::bar() calls E::foo() which calls B::foo() in the SUPER class.
Even though the $e->bar() call was made on line 54, E::foo() gets called on line 47, so you get this: e->bar() = [E, iii.pl, 47, B::foo]
If you were to change B::foo to go one stack frame back like this 'caller(1)', then you get this: e->bar() = [E, iii.pl, 54, E::bar]

Try to put everything in one .pl file when you are experimenting, unless you want to try it with use/require blocks.

Good luck.
-sln

## iii.pl
use strict;
use warnings;

##
package B;
our @ISA = qw();

sub new {
my $this = shift;
return bless { }, ref($this) || $this;
}

sub foo {
my $this = shift;
return join (', ', (caller(0))[0..3]);
}

##
package D;
our @ISA = qw(B);

sub new {
my $this = shift;
my $class = ref($this) || $this;
my $obj = $class->SUPER::new(@_);
return bless $obj, $class;
}

my $d = new D;
print "d->foo() = [", $d->foo(), "]\n";


##
package E;
our @ISA = qw(B);

sub new {
my $this = shift;
my $class = ref($this) || $this;
my $obj = $class->SUPER::new(@_);
return bless $obj, $class;
}

sub bar {
my $this = shift;
return $this->foo();
}


my $e = new E;
print "e->foo() = [", $e->foo(), "]\n";
print "d->foo() = [", $d->foo(), "]\n";
print "e->bar() = [", $e->bar(), "]\n";

__END__

Output:

d->foo() = [D, iii.pl, 31, B::foo]
e->foo() = [E, iii.pl, 52, B::foo]
d->foo() = [E, iii.pl, 53, B::foo]
e->bar() = [E, iii.pl, 47, B::foo]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top