develooper Front page | perl.perl5.porters | Postings from January 2022

Re: Broken stack traces from use statements.

Thread Previous | Thread Next
From:
demerphq
Date:
January 16, 2022 08:32
Subject:
Re: Broken stack traces from use statements.
Message ID:
CANgJU+WbmZNczF3XcuwZjWGUcROfJ4BSfjbAJ3G7pGerpnpL8Q@mail.gmail.com
On Sun, 16 Jan 2022, 15:10 Dan Book, <grinnz@gmail.com> wrote:

> On Sun, Jan 16, 2022 at 1:54 AM demerphq <demerphq@gmail.com> wrote:
>
>> On Sat, 15 Jan 2022 at 14:27, Leon Timmermans <fawaka@gmail.com> wrote:
>>
>>> On Sat, Jan 15, 2022 at 8:22 AM demerphq <demerphq@gmail.com> wrote:
>>>
>>>>
>>>> As far as I can tell, it's an accurate representation of how the
>>> sausage is made. BEGIN blocks aren't implemented the way one would expect
>>> them to, and these stacktraces represent that. They're not false, just very
>>> unhelpful.
>>>
>>
>> I really don't understand your position on this. We see output that says
>> 4 contradictory things, none of which are actually accurate. So which one
>> of the four is true and which ones are false?  I dont think the following
>> statements can all be true simultaneously.
>>
>> main::BEGIN() called at A.pm line 2
>> main::BEGIN() called at B.pm line 2
>> main::BEGIN() called at C.pm line 2
>> main::BEGIN() called at D.pm line 2
>>
>> But main::BEGIN is actually called at -e line 1. I mean, if the BEGIN
>> statement were created in a module it would would A::BEGIN or B::BEGIN. For
>> example:
>>
>> $ perl -MCarp=cluck -le'package Foo; BEGIN { Carp::cluck("in begin") }'
>> in begin at -e line 1.
>> Foo::BEGIN() called at -e line 1
>> eval {...} called at -e line 1
>>
>> I really think this is an important point that keeps getting lost. Sure
>> you can say "this is how the sausage is made", as this is the result of
>> using a single global to track the origin of ALL synthesized BEGIN blocks
>> which are part of a use statement. But that is circular logic. "it is
>> correct and true because that is how it works" could be used to justify
>> leaving unfixed ANY bug we encounter.
>>
>
> No, it is specific to this case because we are talking about a feature
> that itself describes how Perl works. This logic would not be relevant for
> most features.
>

I don't understand this. See below.


>
>> If the output did not say "called at A.pm line 2" but said "fake-frame
>> injected by compiler" or something like that, I could buy the "this is how
>> the sausage is made" argument. But it doesn't. It says something different
>> each time. None of which seem to have any relationship to reality.
>>
>> It seems to me we should be able to agree on whether the output is true,
>> and whether it is correct. I am really struggling to understand why this is
>> controversial. It seems to me we should be able to agree that main::BEGIN
>> *cannot* be called from anywhere but main, and this means that the output
>> claiming that the block was called from a module file cannot be correct.
>>
>
> No one is claiming it is the most useful
>

Useful is a matter of opinion I would like to stay away from. The question
is correctness.

 I don't see why just because this is about how the internals work that we
can't talk about correctness and must restrict ourselves to usefulness,
especially as I am arguing the internals aren't working properly given
expected results.

There are many places within my domain of expertise in the internals where
perl does something that I agree to be incorrect even though it's a "won't
fix" because fixing it is intractable given how the internals work. We/I
don't pretend the behaviour is correct because that is how things work, we
accept they are bugs which we can't or won't fix. Why is this case
different? Admittedly there are cases where the answer is unclear, but I
dont feel that the class of bugs we see from caller() is one of them.

thing to display to the user. Just that it represents what the Perl
> interpreter sees, at least to some extent. The only thing controversial is
> various declarations of what is correct and what must be done, where a
> reasoned discussion and assumption of good faith would be much more
> effective at motivating resolution of your issue.
>

I really don't appreciate being accused of acting with bad faith. Nothing I
have said was intended to be disrespectful nor as far as I can tell was
disrespectful.  If anyone perceives it that way I do apologize in advance
and would be open to discuss it in more detail offline and learn how i
could have expressed my position without being accused of bad faith.

It seems to me that achieving consensus that this behaviour is buggy or not
is required to move forward here. I cannot think of another case where if a
perl function returned different results for the same question (rand aside)
depending on where and when it was called would NOT be a bug.

If it is not a bug we shouldn't change it. If it is a bug we should.
Obviously I feel it is a bug and I have stated two reasons. Those claiming
it's not seem don't seem to address those points at all.  I don't consider
"because that is how perl works" a reasonable answer for the simple fact
that that argument can be applied to any bug in perl.

To recap, my arguments this is a bug are as follows (assuming the code
posted below):

1.
The output shows that:
A::BEGIN() called at D.pm line 2
A::BEGIN() called at C.pm line 2
A::BEGIN() called at B.pm line 2
A::BEGIN() called at A.pm line 2

How can this be true at the same time given the code posted?

2.
Line 2 of A.pm, B.pm, C.pm D.pm are all identical and do not include a use
statement:
BEGIN { Carp::cluck "\n--\nIn ", __PACKAGE__; }

Even if we assume there is an off-by-one error in the line number and say
it is referring to line 3 of the respective modules we see that line 3 of
each is as follows:

A.pm line 3: use B;
B.pm line 3: use C;
C.pm line 3: use D;
D.pm line 3: 1;

So how can caller be returning a true and correct result when it says that
says A::BEGIN was called from D.pm line 3?

3.
Which part of that documentation for caller() explains the current
behaviour? The current behaviour seems to be in direct contravention of the
first three sentences of the documentation of the function:

            Returns the context of the current pure perl subroutine call. In
            scalar context, returns the caller's package name if there is a
            caller (that is, if we're in a subroutine or "eval" or
"require")
            and the undefined value otherwise. caller never returns XS subs
            and they are skipped. The next pure perl sub will appear instead
            of the XS sub in caller's return values. In list context, caller
            returns

                   # 0         1          2
                my ($package, $filename, $line) = caller;

So IMO we have to conclude there is a bug here, either in the docs, or in
the implementation. Occams razor would suggest it is the implementation not
the docs.

Cheers,
Yves
~/tlib$ cat {A..D}.pm
package A;
BEGIN { Carp::cluck "\n--\nIn ", __PACKAGE__; }
use B;
1;
__END__


package B;
BEGIN { Carp::cluck "\n--\nIn ", __PACKAGE__; }
use C;
1;
__END__


package C;
BEGIN { Carp::cluck "\n--\nIn ", __PACKAGE__; }
use D;
1;
__END__


package D;
BEGIN { Carp::cluck "\n--\nIn ", __PACKAGE__; }
1;
__END__


~/tlib$ perl -I. -MCarp -e'use A;'

--
In A at A.pm line 2.
A::BEGIN() called at A.pm line 2
eval {...} called at A.pm line 2
require A.pm called at -e line 1
main::BEGIN() called at A.pm line 2
eval {...} called at A.pm line 2

--
In B at B.pm line 2.
B::BEGIN() called at B.pm line 2
eval {...} called at B.pm line 2
require B.pm called at A.pm line 3
A::BEGIN() called at B.pm line 2
eval {...} called at B.pm line 2
require A.pm called at -e line 1
main::BEGIN() called at B.pm line 2
eval {...} called at B.pm line 2

--
In C at C.pm line 2.
C::BEGIN() called at C.pm line 2
eval {...} called at C.pm line 2
require C.pm called at B.pm line 3
B::BEGIN() called at C.pm line 2
eval {...} called at C.pm line 2
require B.pm called at A.pm line 3
A::BEGIN() called at C.pm line 2
eval {...} called at C.pm line 2
require A.pm called at -e line 1
main::BEGIN() called at C.pm line 2
eval {...} called at C.pm line 2

--
In D at D.pm line 2.
D::BEGIN() called at D.pm line 2
eval {...} called at D.pm line 2
require D.pm called at C.pm line 3
C::BEGIN() called at D.pm line 2
eval {...} called at D.pm line 2
require C.pm called at B.pm line 3
B::BEGIN() called at D.pm line 2
eval {...} called at D.pm line 2
require B.pm called at A.pm line 3
A::BEGIN() called at D.pm line 2
eval {...} called at D.pm line 2
require A.pm called at -e line 1
main::BEGIN() called at D.pm line 2
eval {...} called at D.pm line 2

>

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About