Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Debugger Questions - Variable Scope

by GotToBTru (Prior)
on May 15, 2014 at 22:43 UTC ( [id://1086223]=perlquestion: print w/replies, xml ) Need Help??

GotToBTru has asked for the wisdom of the Perl Monks concerning the following question:

If I run the following code in the debugger:

use strict; my $t = 14; blah(); print "$t\n"; sub blah { my $t = 42; print "$t\n"; }

and I place a watch on $t, it applies to both the main program variable and the subroutine variable, even though they are distinct. When the assignment statement in the subroutine executes, it reports that the value changed from 14 to 42, which is not true. Perl is not confused, the values of the variables stay distinct, but the debugger can't keep the namespaces distinct. Or perhaps it can -- is there a way to tell the debugger I want to watch only the variable in the subroutine?

Also, if I make calls to modules, variables in my code go out of scope. If I am watching them, the debugger halts twice, once to tell me the variable now has no value, and once again to tell me it has reappeared! Is there a way to avoid these halts?

Neither of these issues is more than an annoyance, but just in case I'm missing something ...

Update: simplest solution here.

1 Peter 4:10

Replies are listed 'Best First'.
Re: Debugger Questions - Variable Scope (source++)
by tye (Sage) on May 16, 2014 at 05:42 UTC

    You have the source code. Why don't you take a look at it? Your requested feature is dang simple to add. For example (skipping the re-indenting of some lines in order to make the 'diff' smaller):

    --- perl-5.10.1/lib/perl5db.pl +++ ~/lib/perl5db.pl @@ -1957,9 +1957,14 @@ for ( my $n = 0 ; $n <= $#to_watch ; $n++ ) { $evalarg = $to_watch[$n]; + my $val; + if( ref $evalarg ) { + $val = $$evalarg; + } else { local $onetimeDump; # Tell DB::eval() to not output re +sults # Fix context DB::eval() wants to return an array, but # we need a scalar here. - my ($val) = join( "', '", &eval ); + ($val) = join( "', '", &eval ); + } $val = ( ( defined $val ) ? "'$val'" : 'undef' ); @@ -5289,5 +5294,12 @@ # ... save it. - push @to_watch, $expr; + my $val; + if( $expr =~ /^\$\w+$/ ) { + $evalarg = "\\$expr"; + ( $val ) = &eval; + push @to_watch, $val; + $val = $$val; + } else { + push @to_watch, $expr; # Parameterize DB::eval and call it to get the expression's v +alue @@ -5295,5 +5307,6 @@ # return a list value. $evalarg = $expr; - my ($val) = join( ' ', &eval ); + ($val) = join( ' ', &eval ); + } $val = ( defined $val ) ? "'$val'" : 'undef';

    If you ask for the list of watch expressions, the simple ones will be displayed in a rather useless manner. And you should probably weaken the reference taken as otherwise adding a watch point could prevent a destructor from firing.

    On the plus side, I suspect that the new simple watch points will have less of a performance impact than the previous implementation imposed.

    - tye        

      Almost 3 years later, I actually tried this. It does not appear to work: execution does not stop when the variable changes value, and the L command does not show the watchpoint. My Perl version is 5.8.8; that might be important.

      You're right, the solution is pretty simple. Create a ref to the variable of interest and make the watchpoint the dereferenced value. This has the very slight disadvantage of having to wait until the variable of interest has been created, but avoiding the maddening interruptions is wonderful!

      Program slightly modified for demonstration purposes:

      use strict; my $t = 14; print "$t\n"; $t = 15; print "$t\n"; blah(); print "$t\n"; sub blah { my $t = 42; print "$t\n"; }

      Debug session - Was:

      DB<1> w $t DB<2> c Watchpoint 0: $t changed: old value: '' new value: '14' main::(dbt.pl:4): print "$t\n"; DB<2> c 14 Watchpoint 0: $t changed: old value: '14' new value: '15' main::(dbt.pl:6): print "$t\n"; DB<2> c 15 Watchpoint 0: $t changed: <<<<< the bane of my existence old value: '15' new value: '42' main::blah(dbt.pl:12): print "$t\n"; DB<2> c 42 Watchpoint 0: $t changed: <<<<< just more bane old value: '42' new value: '15' main::(dbt.pl:8): print "$t\n"; DB<2> c 15 Watchpoint 0: $t changed: old value: '15' new value: '' Debugged program terminated.

      Now:

      DB<1> w $t DB<2> c Watchpoint 0: $t changed: old value: '' new value: '14' main::(dbt.pl:4): print "$t\n"; DB<2> W $t DB<3> $z=\$t DB<4> w $$z DB<5> c 14 Watchpoint 0: $$z changed: old value: '14' new value: '15' main::(dbt.pl:6): print "$t\n"; DB<5> c 15 42 15 Watchpoint 0: $$z changed: old value: '15' new value: '' Debugged program terminated.
      But God demonstrates His own love toward us, in that while we were yet sinners, Christ died for us. Romans 5:8 (NASB)

        It does not appear to work: execution does not stop when the variable changes value

        I must misunderstand some of what you wrote. The only times I see it not stopping (in your example output) is exactly those places where I thought you had requested that it not stop.

        and the L command does not show the watchpoint

        Yeah, you might have to debug the code. I don't think I had that problem when I ran it years ago, so I'm not planning on trying to reproduce your problem in order to debug for you at this point (especially since it seems that I am misunderstanding something).

        - tye        

      Could you please elaborate a bit?

      I'm mobile ATM and starring at the code without possibility to test...

      But what I'm figuring out is that you add support for watching a ref to a var.

      Now I'm not sure how this solves the problem since variables in a special scope are not guaranteed to have the same ref after a reenter (like different calls to a function).

      Or am I missing something?

      Cheers Rolf

      ( addicted to the Perl Programming Language)

        I don't see why one should assume that "watch for the value of a particular variable to change" should include "and it might change because a whole different variable comes into existence because you called the function again".

        Feel free to implement your own semantics for "watch". This took me a whole few minutes, including testing it. But when I implement semantics for "watch a variable", I actually want to watch a variable, not "watch whichever instance of a whole class of related variables is currently in scope, if any".

        Another benefit with my approach is that I get notified of changes that happen to the value of the watched variable even when it isn't currently in scope under the same name. That's actually the type of thing that makes "what the heck is changing $x?!" tricky to find which might actually motivate me to want a debugger's "watch" feature. *shrug*

        - tye        

Re: Debugger Questions - Variable Scope
by LanX (Saint) on May 15, 2014 at 23:29 UTC
    IIRC are watch expressions just evaled text, and there is no way to tell plain Perl which pad a lexical var belongs to.

    So no official way AFAIK ...

    ... BUT since watch expressions are just evaled text (sic ;-) you can use hacks to restrict them to a range of lines or to be dependent on caller.

    I'm too lazy now to fiddle around by myself, but this thread should show you some approaches:

    Make debugger break on source lines matching a pattern

    HTH! =)

    Cheers Rolf

    ( addicted to the Perl Programming Language)

      Some ideas to explore here. The YAPC talk referenced seems especially interesting for this problem and others.

      1 Peter 4:10
        > The YAPC talk referenced seems especially interesting for this problem and others.

        hmm not really, I didn't try to mess with "watch".

        I'm personally using and testing my patched version for years now, and there are edge cases where it fails.

        The debugger really needs refactoring and modularization.

        For instance the command-loop spreads over hundreds and hundreds of lines with if-blocks on regex-conditions and interwoven POD as documentation, where order matters. Thats extremely hard to patch.

        Plus there doesn't seem to be any test suite. :(

        Cheers Rolf

        ( addicted to the Perl Programming Language)

Re: Debugger Questions - Variable Scope
by Laurent_R (Canon) on May 16, 2014 at 06:16 UTC
    This behavior of the debugger is exactly what I would expect and hope to get, and I would curse any other behavior. If I watch some $t variable, I really want to know what will happen if I use this variable anywhere in my code. Semantically, it is true that you really have two different $t variables, one scoped to the program, and another one scoped to the subroutine. But from the standpoint of what the code does and sees, or of what I see when I read the code, you have only one variable name. So if my code uses this variable name, I really wish the debugger to tell me that this variable name now refers to a different content. The debugger is doing it right on this issue.

      I see your point here and I agree - that should remain the default behavior. I would like the option of telling the debugger to ignore certain instances of change, such as the variable becoming undefined when executing code in another package. I'm voluntarily blinding myself by doing this to cut down on the noise.

      1 Peter 4:10
Re: Debugger Questions - Variable Scope
by LanX (Saint) on May 16, 2014 at 18:23 UTC
    using tye's reference approach without patching the sources:

    You could use actions to set and unset a global variable holding a ref to the variable to be watched:

    something like the following watches between the lines 10 and 13 only!

    DB<2> a 10 $WATCH=\$t DB<3> a 13 $WATCH=\undef DB<4> w ${$WATCH}

    IMHO you could even define your own alias in .perldb to automate this.

    something like rw 10-13 $t for "regional watch".

    Tye's remarks about weakening to avoid leaks are still valid...

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1086223]
Approved by toolic
Front-paged by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-03-29 07:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found