Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is it OK to use an undefined variable in perl with warnings enabled?

With warnings enabled, perl usually prints Use of uninitialized value $foo if $foo is used in an expression and hasn't been assigned a value, but in some cases it's OK, and the variable is treated as false, 0, or '' without a warning.

What are the cases where an uninitialized/undefined variable can be used without a warning?

like image 866
Frank Szczerba Avatar asked Jan 30 '10 02:01

Frank Szczerba


People also ask

What are warnings in Perl?

use warnings; When the warning pragma is used, the compiler will check for errors, will issue warnings against the code, and will disallow certain programming constructs and techniques. This pragma sends a warning whenever a possible typographical error and looks for possible problems.

How do I check if a variable is undefined in Perl?

Perl | defined() Function Defined() in Perl returns true if the provided variable 'VAR' has a value other than the undef value, or it checks the value of $_ if VAR is not specified. This can be used with many functions to detect for the failure of operation since they return undef if there was a problem.

What is undef in Perl?

undef is used for those variables which do not have any assigned value. One can compare it with NULL(in Java, PHP etc.) and Nil(in Ruby). So basically when the programmer will declare a scalar variable and don't assign a value to it then variable is supposed to be contain undef value.

How do I empty a variable in Perl?

To tell if a variable has already been defined in a perl program, you can use the function defined . If you wish to wipe away all traces of a variable at some point in a program, you can use the undef function, or simply set the variable equal to the value undef .


2 Answers

Summary

  • Boolean tests
  • Incrementing or decrementing an undefined value
  • Appending to an undefined value
  • Autovivification
  • Other mutators

Boolean tests

According to the perlsyn documentation,

The number 0, the strings '0' and '', the empty list (), and undef are all false in a boolean context. All other values are true.

Because the undefined value is false, the following program

#! /usr/bin/perl

use warnings;

my $var;
print "A\n" if $var;
$var && print "B\n";
$var and print "C\n";
print "D\n" if !$var;
print "E\n" if not $var;
$var or print "F\n";
$var || print "G\n";

outputs D through G with no warnings.

Incrementing or decrementing an undefined value

There's no need to explicitly initialize a scalar to zero if your code will increment or decrement it at least once:

#! /usr/bin/perl

use warnings;

my $i;
++$i while "aaba" =~ /a/g;
print $i, "\n";

The code above outputs 3 with no warnings.

Appending to an undefined value

Similar to the implicit zero, there's no need to explicitly initialize scalars to the empty string if you'll append to it at least once:

#! /usr/bin/perl

use warnings;
use strict;

my $str;
for (<*>) {
  $str .= substr $_, 0, 1;
}
print $str, "\n";

Autovivification

One example is "autovivification." From the Wikipedia article:

Autovivification is a distinguishing feature of the Perl programming language involving the dynamic creation of data structures. Autovivification is the automatic creation of a variable reference when an undefined value is dereferenced. In other words, Perl autovivification allows a programmer to refer to a structured variable, and arbitrary sub-elements of that structured variable, without expressly declaring the existence of the variable and its complete structure beforehand.

For example:

#! /usr/bin/perl

use warnings;

my %foo;
++$foo{bar}{baz}{quux};

use Data::Dumper;
$Data::Dumper::Indent = 1;
print Dumper \%foo;

Even though we don't explicitly initialize the intermediate keys, Perl takes care of the scaffolding:

$VAR1 = {
  'bar' => {
    'baz' => {
      'quux' => '1'
    }
  }
};

Without autovivification, the code would require more boilerplate:

my %foo;
$foo{bar} = {};
$foo{bar}{baz} = {};
++$foo{bar}{baz}{quux};  # finally!

Don't confuse autovivification with the undefined values it can produce. For example with

#! /usr/bin/perl

use warnings;

my %foo;
print $foo{bar}{baz}{quux}, "\n";
use Data::Dumper;
$Data::Dumper::Indent = 1;
print Dumper \%foo;

we get

Use of uninitialized value in print at ./prog.pl line 6.

$VAR1 = {
  'bar' => {
    'baz' => {}
  }
};

Notice that the intermediate keys autovivified.

Other examples of autovivification:

  • reference to array

    my $a;
    push @$a => "foo";
    
  • reference to scalar

    my $s;
    ++$$s;
    
  • reference to hash

    my $h;
    $h->{foo} = "bar";
    

Sadly, Perl does not (yet!) autovivify the following:

my $code;
$code->("Do what I need please!");

Other mutators

In an answer to a similar question, ysth reports

Certain operators deliberately omit the "uninitialized" warning for your convenience because they are commonly used in situations where a 0 or "" default value for the left or only operand makes sense.

These are: ++ and -- (either pre- or post-), +=, -=, .=, |=, ^=, &&=, ||=.

Being "defined-or," //= happily mutates an undefined value without warning.

like image 127
Greg Bacon Avatar answered Oct 25 '22 20:10

Greg Bacon


So far the cases I've found are:

  • autovivification (gbacon's answer)
  • boolean context, like if $foo or $foo || $bar
  • with ++ or --
  • left side of +=, -=, or .=

Are there others?

like image 21
Frank Szczerba Avatar answered Oct 25 '22 18:10

Frank Szczerba