Perl: Variable value is 'glob', but should be 'scalar'

Viewed 104

I do have the following simple code:

my $TimeZone = $hCache->{'TimeZone'}; # Cache gets filled earlier
my $DateTime = DateTime->now();
$DateTime->set_time_zone($TimeZone);

This code runs in an application server which is basically a long running perl process that accepts incoming network connections.

From time to time this applicationserver gets somehow "dirty", and the code above is printing the following error:

The 'name' parameter ("Europe/Berlin") to DateTime::TimeZone::new was a 'glob', which is not one of the allowed types: scalar at /srv/epages/eproot/Perl/lib/site_perl/linux/DateTime.pm line 1960.

When I try to debug the variable "$TimeZone" I'm getting no further details.

E.g.

print ref($TimeZone); # prints nothing (scalar?)
print $TimeZone; # prints "Europe/Berlin"

The code works if I'm forcing the timezone to be a string again, like so:

my $TimeZone = $hCache->{'TimeZone'}; # Cache gets filled earlier
my $DateTime = DateTime->now();
$DateTime->set_time_zone($TimeZone."");

My questions are:

  1. If 'glob' is not a reference, how can I debug the variable properly?
  2. How can I create a 'glob' variable? What is the syntax to it? I'm quite sure that my huge codebase has some accidents in it, but I don't know what to search for.
  3. Is there a way to 'monitor' the variable? Basically, getting a stacktrace if the variable changes
1 Answers

How can I create a 'glob' variable?

Glob, short for "typeglob" is a structure (in the C sense of the word) that contains a field for each type of variable that can be found in the symbol table (scalar, array, hash, code, glob, etc). They form the symbol table.

Globs are created by simply mentioning a package variable.

@a = 4..6;      # Creates glob *main::a containing a reference to the new array.

Since globs are themselves packages variables, you can bring a glob into existence just by mentioning it.

my $x = *glob;  # The glob *main::glob is created by this line at compile-time.

Note that file handles are often accessed via globs. For example, open(my $fh, '<', ...) populates $fh with a reference to a glob that contains a reference to an IO.

$fh        # Reference to glob that contains a reference to an IO.
*$fh       # Glob that contains a reference to an IO.
*$fh{IO}   # Reference to an IO.

If 'glob' is not a reference, how can I debug the variable properly?

ref(\$var) will return GLOB for a glob.

$ perl -e'$x = *STDOUT; CORE::say ref(\$x)'
GLOB

Is there a way to 'monitor' the variable?

Yes. You can add magic to it.

$ perl -e'
   use feature qw( say );

   use Carp            qw( cluck );
   use Variable::Magic qw( wizard cast );

   my $wiz = wizard(
      data => sub { $_[1] },
      set  => sub { cluck("Variable $_[1] modified"); },
   );

   my $x;
   cast($x, $wiz, q{$x});
   $x = 123;                     # Line 14
'
Variable $x modified at -e line 9.
        main::__ANON__(SCALAR(0x50bcee23c0), "\$x") called at -e line 14
        eval {...} called at -e line 14

More work is needed to detect if a hash or array changes, but the above can be used to monitor the elements of hashes and arrays.

Related