NAME

Devel::WatchVars - trace access to scalar variables

SYNOPSIS

use Devel::WatchVars qw(watch unwatch);

Start tracing:

watch $some_var,    '$some_var'; # single quotes so it knows its name
watch $nums[2],     'element[2] of the @nums array';
watch $color{blue}, 'the blue element of the %color hash';

######################################
# Do things that access those, then...
######################################

End tracing:

unwatch $color{blue};
unwatch $nums[2];
unwatch $some_var;

DESCRIPTION

The Devel::WatchVars module provides simple tracing of scalars. The watch function takes the scalar you want traced followed by the descriptive string to use as its name in traces.

Here's a simple illustration using a short program, here named examples/simple:

 1	#!/usr/bin/env perl
 2	use v5.10;
 3	use strict;
 4	use warnings;
 5	
 6	use Devel::WatchVars;
 7	sub twice { return 2 * shift  }
 8	
 9	my $x = 10;
10	watch($x, '$x');
11	say "starting watched value is $x";
12	$x = 5 + twice(++$x);
13	say "ending watched value is $x";
14	unwatch $x;

When run, that produces the following output:

WATCH $x = 10 at examples/simple line 10.
FETCH $x --> 10 at examples/simple line 11.
starting watched value is 10
FETCH $x --> 10 at examples/simple line 12.
STORE $x <-- 11 at examples/simple line 12.
FETCH $x --> 11 at examples/simple line 7.
STORE $x <-- 27 at examples/simple line 12.
FETCH $x --> 27 at examples/simple line 13.
ending watched value is 27
UNWATCH $x = 27 at examples/simple line 14.

The trace appears on standard error, one line per access consisting of the following elements:

  • A word in all capital letters for the type of access, one of WATCH, FETCH, STORE, UNWATCH, or DESTROY.

  • Whatever string you passed in the second argument. passed the initial call to watch.

  • A bit of intervening text (= or --> or <--).

  • The scalar value.

  • The origin by file and line.

The first argument to watch must be a scalar variable, or a single scalar element from an array or a hash. In other words, that argument needs to begin with a literal dollar sign.

The second argument to watch is an arbitrary string. Normally its the name of that watched scalar, however you choose to represent that. This can be useful if you just want to watch one element from some larger data structure. For example,

watch $nums[2],     "element[2] of array";

watch $color{blue}, "the blue color element";

The argument to unwatch must match one that you have previously called watch with and which you have not yet called unwatch with.

The tracing lasts until you call the unwatch function on the watched variable to discontinue that tracing, or when that scalar is destroyed through garbage collection. If it is destroyed while the program is running, it will say something like:

DESTROY $x = 9 at examples/destroyed line 15.

but if is destroyed during global destruction, it indicates this like so:

DESTROY (during global destruction) $x = 9 at examples/global-destruction line 0.

The watch function is implemented using an internal tie, and the unwatch function is implemented using an internal untie.

EXAMPLES

See the example scripts in the examples subdirectory of this module's source distribution.

ENVIRONMENT

DEVEL_WATCHVARS_VERBOSE

Normally, the traces include only a shortmess at the end, no matter what you've may have set the value of $Carp::Verbose to. But if the environment variable DEVEL_WATCHVARS_VERBOSE has a true value, a full longmess will be used instead.

DIAGNOSTICS

"Can't unwatch something that isn't tied"

Runtime error because the scalar you passed is not being watched right now.

"Can't unwatch something that isn't watched"

Runtime error because the scalar you passed is tied to some other class.

"Can't watch a readonly scalar"

The scalar variable you want to watch contains a readonly value.

"Type of arg 1 to Devel::WatchVars::unwatch must be scalar (not %s)"

Attempting to pass something to unwatch that does not begin with a literal dollar sign will produce a compilation error in your code like this:

Type of arg 1 to Devel::WatchVars::unwatch must be scalar (not hash dereference) at -e line 1
"Type of arg 1 to Devel::WatchVars::watch must be scalar (not %s)"

Attempting to pass something to watch that does not begin with a literal dollar sign will produce a compilation error in your code like these:

Type of arg 1 to Devel::WatchVars::watch must be scalar (not constant item) at -e line 1

Type of arg 1 to Devel::WatchVars::watch must be scalar (not array dereference) at -e line 1
"You didn't pass a scalar (by reference)";
"You didn't pass a SCALAR (by reference), you passed a %s (by reference)"

These are both runtime errors, and usually possible only if you're cheating by calling the functions without prototypes being checked.

TODO

Devise a curried subclassing mechanism.

Add watching entire aggregate arrays and hashes en masse.

SEE ALSO

Tie::Watch

Place watchpoints on Perl variables using PerlTK.

Devel::TraceVars

Mode of the perl debugger to print each line of code with variables evaluated.

AUTHOR

Tom Christiansen <tchrist53147@gmail.com>.

LICENCE AND COPYRIGHT

Copyright (c) 2020-2021 by Tom Christiansen.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.