alain_desilets has asked for the wisdom of the Perl Monks concerning the following question:
Hi folks,
I have been using 'use strict' for years, but was only recently introduced to 'use warnings'. While I find it generally useful, it tends to generate warnings in contexts where I think it shouldn't, in particular when trying to print a variable whose value is undef.
For example, consider the following code:
use strict;
use warnings;
my @some_array = (1, 2, undef, 4, 5);
for (my $ii=0; $ii < scalar(@some_array); $ii++) {
print "Value at position $ii: $some_array[$ii]\n";
}
This code prints the elements of an array, some of which have value undef. If you run it, you get error messages
"Use of uninitialized value $some_array2 in concatenation (.) or string at etc..."
Yet, it's perfectly fine for an array to contain some values of undef. Why shouldn't I be allowed to print them?
Is there a way around this issue? Thx.
Re: Annoying 'Use of uninitialized value in concatenation' warning
by runrig (Abbot) on Oct 25, 2011 at 19:55 UTC
|
If you don't care about uninitialized warnings in your loop then put in your loop: no warnings 'uninitialized';
If you don't care about uninitialized warnings in the entire script, then put that line right underneath the use warnings line.
If you don't care about any sort of warnings at all, then don't include a use warnings line. | [reply] [d/l] [select] |
Re: Annoying 'Use of uninitialized value in concatenation' warning
by BrowserUk (Patriarch) on Oct 25, 2011 at 20:09 UTC
|
Yet, it's perfectly fine for an array to contain some values of undef. Why shouldn't I be allowed to print them?
Because you cannot "print undef"!
Without the warning, there is no way to distinguish between print ''; and print undef;.
Which may be fine in some contexts, but can be strongly indicative of a serious error in others.
Hence the warning is optional and turn on and off able. You can choose to turn it off in individual blocks of code, or if you feel it never benefits you, turn it off at the top of the module: use warnings; no warnings 'uninitialized';
It's a shame there isn't a better syntax for enabling everything except one or two categories.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
|
I agree with BrowserUk, I think it's important to know when you are trying to use an initialized variable. Good to know that you can turn it off when needed. Your other option is to used empty strings instead of undef.
| [reply] |
|
I also agree ... completely.
“Warnings are your friends,” because the only party that can realistically tell you what a computer program is doing wrong is ... the computer itself. Nevertheless you may decide that there are specific places in your program where an innocuous condition such as this one is causing a boatload of unwanted error-messages, e.g. in an Apache error log, and therefore you justifiably want to stamp the message out because it’s doing more harm than good. In those cases, Perl does allow you to do that. And, as BrowserUK wisely suggests, when you elect to do such a thing, you ought to do so in a very targeted way. Suppress only the specific warnings you need to suppress, and do so only within a limited section of the code. (I further advise that you add detailed comments surrounding the area: “exactly what are you intending to suppress, and exactly why.” Copying a representative handful of the actual message-texts and pasting them right into the comment-block is a pretty good idea to me, ’cuz you will forget these things.)
Fav’d.
| [reply] |
Re: Annoying 'Use of uninitialized value in concatenation' warning
by Perlbotics (Archbishop) on Oct 25, 2011 at 20:06 UTC
|
You can silence the warning (if you know what you do) or you can detect and treat the undef-case. However, it is wise to keep the no warnings; scope small.
Update: See also johngg's hint below about the do{ ... } trick.
When in doubt, I suggest to treat the undef-case, and let the warning pragma do its job.
Often, an undef warning reveals a bug that was otherwise undetected.
use strict;
use warnings;
sub original_post {
my @some_array = (1, 2, undef, 4, 5);
for (my $ii=0; $ii < scalar(@some_array); $ii++) {
print "Value at position $ii: $some_array[$ii]\n";
}
}
sub detect_undef_and_set {
my @some_array = (1, 2, undef, 4, 5);
#alternative-1: fix data structure
# @some_array = map { $_ // '(oops! undef!!)' } @some_array;
for (my $ii=0; $ii < scalar(@some_array); $ii++) {
#alternative-2: fix output
print "Value at position $ii: ", $some_array[$ii] // '(oops! undef
+!)' , "\n";
}
}
sub no_warnings {
my @some_array = (1, 2, undef, 4, 5);
for (my $ii=0; $ii < scalar(@some_array); $ii++) {
no warnings 'uninitialized'; # for this lex scope only
print "Value at position $ii: $some_array[$ii]\n";
}
}
print "ORIG:\n"; original_post();
print "CHECK:\n"; detect_undef_and_set();
print "NO WARN:\n"; no_warnings();
__DATA__
RIG:
Value at position 0: 1
Value at position 1: 2
Use of uninitialized value $some_array[2] in concatenation (.) or stri
+ng at nowarn.pl line 7.
Value at position 2:
Value at position 3: 4
Value at position 4: 5
CHECK:
Value at position 0: 1
Value at position 1: 2
Value at position 2: (oops! undef!)
Value at position 3: 4
Value at position 4: 5
NO WARN:
Value at position 0: 1
Value at position 1: 2
Value at position 2:
Value at position 3: 4
Value at position 4: 5
| [reply] [d/l] [select] |
|
for (my $ii=0; $ii < scalar(@some_array); $ii++) {
print do {
no warnings 'uninitialized'; # for the do block only
"Value at position $ii: $some_array[$ii]\n";
};
}
I hope this is of interest.
| [reply] [d/l] [select] |
Re: Annoying 'Use of uninitialized value in concatenation' warning
by toolic (Bishop) on Oct 25, 2011 at 20:09 UTC
|
| [reply] |
|
Thx. I was already familiar with the "no warning 'xyz'", but I hadn't found the names of all the warning categories.
Alain
| [reply] |
|
If you use diagnostics perl will tell you which category the warning belongs to. For example, printing an uninitialised variable yields (the category is in bold):
Use of uninitialized value $x in print at
/home/bri/foo.pl line 14 (#1)
(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.
Additionally, perldiag lists all of perl's warning and error messages.
| [reply] |
Re: Annoying 'Use of uninitialized value in concatenation' warning
by GrandFather (Saint) on Oct 26, 2011 at 01:40 UTC
|
use warnings;
use strict;
use 5.010;
my @some_array = (1, 2, undef, 4, 5);
for (my $ii = 0; $ii < scalar(@some_array); $ii++) {
print "Value at position $ii: @{[$some_array[$ii] // '--undef--']}
+\n";
}
Prints:
Value at position 0: 1
Value at position 1: 2
Value at position 2: --undef--
Value at position 3: 4
Value at position 4: 5
True laziness is hard work
| [reply] [d/l] [select] |
|
another option without concatenation:
print "Value at position $ii: ", $some_array[$ii] || '--undef--',"\n";
| [reply] [d/l] |
|
The problem with using the || (logical-or) operator (see perlop) in this case is that the undefined value is false, as are 0, '0' and '' (the empty string), and || does not distinguish. If your Perl version is 5.10+, you can use the // (defined-or) operator; otherwise, you're stuck with syntax that's a bit more messy:
c:\@Work\Perl\monks>perl -wMstrict -le
"use 5.010;
;;
my @ra = (0, 0, 0);
;;
my $i = 1;
print qq{value at index $i: }, $ra[$i] || 'undef';
print qq{value at index $i: }, $ra[$i] // 'undef';
print qq{value at index $i: }, defined($ra[$i]) ? $ra[$i] : 'undef'
"
value at index 1: undef
value at index 1: 0
value at index 1: 0
Give a man a fish: <%-(-(-(-<
| [reply] [d/l] [select] |
Re: Annoying 'Use of uninitialized value in concatenation' warning
by mbethke (Hermit) on Oct 25, 2011 at 20:47 UTC
|
What runrig said.
The reason for having a warning about this is that while undef is a perfectly valid value for a variable, it has no textual representation. Printing it will render it as an empty string but Perl will warn you that what you're seeing may not be what you wanted. More often than not, having undefs printed indicates that you forgot to calculate/read/whatever some value.
| [reply] |
|
The reason for having a warning about this is that while undef is a perfectly valid value for a variable, it has no textual representation.
Bullshit.
There are also characters that have no textual representation, and using them doesn't warn.
Note that the warning from the OP isn't even about printing - it's about concatenation. There's a perfectly good reason why most operations warn if one of its operands is undefined, but having no textual representation isn't that reason.
| [reply] |
|
|