Monday, September 26, 2016

Tattletale Variables

Sometimes you might be faced with a huge program that, somewhere, is changing a variable's value to something undesired.

  1. use Data::Dumper;
  2. sub some_long_faraway_function {
  3. my $href = shift;
  4. # Pretend there's a lot of code here I don't want to sift through
  5. $href->{bananas} = 'some bad value';
  6. }
  7. my $shopping_list = {
  8. apples => 1,
  9. pears => 3,
  10. bananas => 5,
  11. };
  12. some_long_faraway_function($shopping_list);
  13. warn Dumper(\$shopping_list);

Output:

$VAR1 = \{
            'apples' => 1,
            'bananas' => 'some bad value',
            'pears' => 3
        };

You don't know where it's being changed, but you need to find out. Change the variable so that it tells you where it's being changed.

  1. package TattletaleScalar;
  2. use Carp qw(cluck);
  3. require Tie::Scalar;
  4. our @ISA = qw(Tie::StdScalar);
  5. sub STORE {
  6. warn "TATTLETALE variable set to {$_[1]}";
  7. cluck();
  8. ${$_[0]} = $_[1];
  9. }
  10. package main;
  11. use Data::Dumper;
  12. sub some_long_faraway_function {
  13. my $href = shift;
  14. # Pretend there's a lot of code here I don't want to sift through
  15. $href->{bananas} = 'some bad value';
  16. }
  17. my $shopping_list = {
  18. apples => 1,
  19. pears => 3,
  20. bananas => 5,
  21. };
  22. my $tmp = $shopping_list->{bananas}; # Save current value
  23. tie $shopping_list->{bananas}, 'TattletaleScalar';
  24. $shopping_list->{bananas} = $tmp; # Restore saved value
  25. some_long_faraway_function($shopping_list);
  26. warn Dumper(\$shopping_list);

Now we can see the stack every time the variable is changed:

TATTLETALE variable set to {5} at example.pl line 7.
at example.pl line 8.
    TattletaleScalar::STORE(TattletaleScalar=SCALAR(0x7fac290d3260), 5) called at example.pl line 29
TATTLETALE variable set to {some bad value} at example.pl line 7.
at example.pl line 8.
    TattletaleScalar::STORE(TattletaleScalar=SCALAR(0x7fac290d3260), "some bad value") called at example.pl line 19
    main::some_long_faraway_function(HASH(0x7fac29026508)) called at example.pl line 30
$VAR1 = \{
            'apples' => 1,
            'pears' => 3,
            'bananas' => 'some bad value'
        };

No comments: