Use of uninitialized value: when don't you get that?

T

Tim McDaniel

I like to have "use strict" and "use warnings" (actually, "-w" on my
scripts). I'm now wondering: when can you use an undefined value and
not get the "Use of uninitialized value" warning. Experimentally, I
don't get the warning with

my $x = undef;
my $y = undef;
if ($y) { ... }
if (! $y) { ... }
if ($y && ! $y) { ... }
if (exists $x->{notdef}) { ... }
if (defined $x->{notdef}) { ... }
if ($x->{notdef}) { ... }
# and none of those autovivify it.

(at least under Perl 5.008008, which is what my workplace uses).

Is there a more complete listing of conditions that cause the warning
and/or those that do not? I consider "using the value" to be an
insufficient explantion, because I consider "if ($y)" to be a use of
the value. "Using the value with an operator" covers cases like "+"
and "." and "eq", but it doesn't work for me because "&&" is an
operator too.
 
L

Lucien Coffe

Tim McDaniel wrote :
I like to have "use strict" and "use warnings" (actually, "-w" on my
scripts).

I think the "use warnings" way is the recommended way. It is scoped to
the file/package, and is clearer.
I'm now wondering: when can you use an undefined value and
not get the "Use of uninitialized value" warning. Experimentally, I
don't get the warning with

my $x = undef;
my $y = undef;
if ($y) { ... }
if (! $y) { ... }
if ($y && ! $y) { ... }
if (exists $x->{notdef}) { ... }
if (defined $x->{notdef}) { ... }
if ($x->{notdef}) { ... }
# and none of those autovivify it.

(at least under Perl 5.008008, which is what my workplace uses).

Is there a more complete listing of conditions that cause the warning
and/or those that do not? I consider "using the value" to be an
insufficient explantion, because I consider "if ($y)" to be a use of the
value. "Using the value with an operator" covers cases like "+" and "."
and "eq", but it doesn't work for me because "&&" is an operator too.

Put it that way : *undef* can be true or false; In list context it is
true, in all scalar contexts it is false. So testing it is not a problem.

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

my $x = undef;
print 1,"\n" if( [ $x ] ); # true
print 2,"\n" if( $x ); # false
print 3,"\n" if( $x++ ); # false

$x = undef;
print 4,"\n" if( ++$x ); # true

$x = undef;
print 5,"\n" if ref $x; # false
print 6,"\n" if( $x->{foo} ); # true
print 7,"\n" if ref $x; # now true, ref $x = HASH

$x = undef;
print 8,"\n" if( "$x" ); # w uninitialized
print 9,"\n" if( $x == 1 ); # w uninitialized


Output from the diagnostics pragma :

(W uninitialized) An undefined value was used as if it were already
defined. It was interpreted as a "" or a 0, but maybe it was a mistake.
To suppress this warning assign a defined value to your variables.

So if you use undef explicitly as a string or as a numeric value, you get
the warning. Hope this helps.
 
L

Lucien Coffe

Lucien Coffe wrote :
So if you use undef explicitly as a string or as a numeric value, you
get the warning.

* If you use it explicitly as a string, or if you compare it as a
numerical value.
 
L

Lucien Coffe

Lucien Coffe wrote :
Lucien Coffe wrote :


* If you use it explicitly as a string, or if you compare it as a
numerical value.

Bumping again.

$x = undef;
print 10,"\n" if( $x+1 ); # w uninitialized

undef++ is undef, ++undef is 1, undef+1 triggers the warning because you
try to interpret undef to it's numerical value to use the + operator.
Someone correct me if I'm wrong.
 
T

Tim McDaniel

Tim McDaniel wrote :


I think the "use warnings" way is the recommended way. It is scoped
to the file/package, and is clearer.

Quite so, quite so. I was thinking of the scripts that I've done for
myself, where there's just one file and I'm invoking it as a command.
(I started with Perl 4.036, I think: I'm pretty sure "use warnings"
didn't exist; I don't remember whether "my" even existed, and I
suspect not.)
 
T

Tim McDaniel

Put it that way : *undef* can be true or false; In list context it is
true, in all scalar contexts it is false.

As I understand it, a boolean context is not a list context, and if
you use undef in a list context, it's put into a list of one element,
which evaluates as true regardless of what that element is.

My understanding is that there is really no undef in a list context:
if you use it in a list context, it is put into a list of one element,
and a list of one element evaluates as true in a boolean context
regardless of what that element is.
my $x = undef;
print 1,"\n" if( [ $x ] ); # true

That's testing [...], not undef or lists.

print 1.1,"\n" if( [ ] );

prints 1.1. [...] generates a reference to a list, and a reference to
a list evaluates as true regardless of what the elements are or even,
apparently, whether there are even any elements.
print 6,"\n" if( $x->{foo} ); # true

False in 5.014002 on NetBSD, 5.008008 on something, and I would be
astonished if it were true anywhere.
print 7,"\n" if ref $x; # now true, ref $x = HASH

That's true.


Looking further at "man perldiag":

Use of uninitialized value%s

(W uninitialized) An undefined value was used as if it were
already defined. It was interpreted as a "" or a 0, but maybe it
was a mistake. ...

I'm thinking that the first sentence is somewhat imprecise or unclear.
I think the second sentence is the condition: "Use of uninitialized
value" occurs if and only if you use an undef value with an operator
that requires numeric operands (like +, *, ==) or string operands
(like ., printf "%s", split), and not otherwise.

But I'd like to hear from someone authoritative, like someone who
knows how to navigate the source for "perl".
 
R

Rainer Weikusat

[...]

Put it that way : *undef* can be true or false; In list context it is
true, in all scalar contexts it is false.

This is wrong. Invoking a subroutine returning undef in list context
effectivelty causes that to return a list containing a single element
whose value is 'the undefined value'. If this list is assigned to an
array and the array then evaluated in scalar context, the result will
be the number 1 which is regarded as true:

[rw@sapphire]~ $perl -de 0

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(-e:1): 0
DB<1> sub axtmoerder { return undef; }

DB<2> @a = axtmoerder

DB<3> p scalar(@a)
1
DB<4> p $a[0] || 3
3

[...]
Output from the diagnostics pragma :

(W uninitialized) An undefined value was used as if it were already
defined. It was interpreted as a "" or a 0, but maybe it was a mistake.
To suppress this warning assign a defined value to your variables.

I really think 'we' need another warning whose diagnostics output
should roughly be like this:

An addition operator was used. This was interpreted as an
addition but maybe it was a mistake. To suppress this warning,
add the comment # I mean it !!1 to the corresponding line of
the code.
 
T

Tim McDaniel

Is there a more complete listing of conditions that cause the warning
and/or those that do not?

I hit on the right search terms (if only I knew what they were).
http://www.perlmonks.org/?node_id=862 by ambrus, from 2005, points to
perlsyn. The current version says

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Declarations

The only things you need to declare in Perl are report formats and
subroutines (and sometimes not even subroutines). A variable holds
the undefined value ("undef") until it has been assigned a defined
value, which is anything other than "undef". When used as a number,
"undef" is treated as 0; when used as a string, it is treated as the
empty string, ""; and when used as a reference that isn't being
assigned to, it is treated as an error. If you enable warnings,
you'll be notified of an uninitialized value whenever you treat
"undef" as a string or a number. Well, usually. Boolean contexts,
such as:

my $a;
if ($a) {}

are exempt from warnings (because they care about truth rather than
definedness). Operators such as "++", "--", "+=", "-=", and ".=",
that operate on undefined left values such as:

my $a;
$a++;

are also always exempt from such warnings.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I would put it as: A Boolean context is a scalar context, but it does
not convert values to be either string or a number. Therefore, undef
in a boolean context evaluates as false without producing a
uninitialized warning.

Also, "when used as a reference that isn't being assigned to, it is
treated as an error" does not appear to be accurate.

$x = undef;
if (exists $x->{notdef}) {
print "Huh?\n";
}
printf "after bad ref #3 [%s] [%d] [%s]\n", ref $x,
scalar keys %{$x}, join(',', keys %{$x});

produces only

after bad ref #3 [HASH] [0] []

That is, it doesn't create a something->{notdef} element, but it does
assign $x a reference to a new hash, and there's no error or warning.
I need to go read up on autovivification.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top