lc() with undefined arg

L

Len

I expected this to give a warning for "uninitialized value" :
perl -w -e 'my $abc; print "\L$abc";'
But it doesn't!

Why is this different from:
perl -w -e 'my $abc; print "$abc";'
which DOES give the expected warning ?

Is it documented that lc() doesn't mind an undefined argument ?
Or is something else going on?

I'm interested in this because the following would be kind of neat
if I could trust that it would work cleanly into the future,
even if Flag was missing from the hash:
if ("\L$hash->{'Flag'}" eq 'yes') {...}

If I don't understand why it works, I'll continue to use the rather
messier:
if (lc ($hash->{'Flag'} || '') eq 'yes') {...}

(BTW, about omitting the quotes, as in $hash->{Flag} :
is this considered sound practice, or is it just lazy ?)

Cheers,

-Len
 
P

Paul Lalli

I expected this to give a warning for "uninitialized value" :
perl -w -e 'my $abc; print "\L$abc";'
But it doesn't!

Why is this different from:
perl -w -e 'my $abc; print "$abc";'
which DOES give the expected warning ?

Is it documented that lc() doesn't mind an undefined argument ?

Not that I can see anywhere, but that certainly does seem to be the
case:

perl -MData::Dumper -wle '$bar = lc($foo); print Dumper(\$foo, \$bar);'
$VAR1 = \undef;
$VAR2 = \'';
if (lc ($hash->{'Flag'} || '') eq 'yes') {...}

(BTW, about omitting the quotes, as in $hash->{Flag} :
is this considered sound practice, or is it just lazy ?)

It could come back to bite you one day if: 1) a future release of Perl
suddenly introduces a Flag() function; 2) your code is modified to
include a Flag() subroutine; 3) your code is modified to import a
module which exports a Flag() subroutine; 4) your code is modified to
include a constant named Flag. If you're worried about one or more of
those, much safer to use the quotes.

Paul Lalli

Paul Lalli
 
L

Len

Is it documented that lc() doesn't mind an undefined argument ?
Not that I can see anywhere, but that certainly does seem to be the
case:

Thanks, Paul, for the quick reply. If no one can assure me that
this is documented behavior, I won't depend on it.

Should this failure to warn be reported as a bug?
If so, what is the best way to do that?

Cheers,
-Len
 
P

Paul Lalli

Thanks, Paul, for the quick reply. If no one can assure me that
this is documented behavior, I won't depend on it.

Should this failure to warn be reported as a bug?
If so, what is the best way to do that?

I'm not convinced that it is a bug. Unexpected and undocumented,
certainly. But I think a "bug" is something that directly contradicts
the documentation. I think this just qualifies as "undefined
behavior." Regardless, the proper way to submit Perl bug reports is
via perlbug. Read about its use at:
perldoc perlbug

Paul Lalli
 
P

Paul Lalli

Stephen said:
Not true.

A simple expression (like a single token) inside the {} will
automatically be treated as quoted, so the following:

perl -w -MData::Dumper -e 'sub foo { return "bar"; } my %h; $h{foo} =
"baz"; print Dumper(\%h)'

will give the expected:

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

Hrm. I was just completely wrong. I was misremembering the docs.
Thanks very much for the correction. An my apologies to the OP for the
misinformation.

Paul Lalli
 
S

Stephen Hildrey

Is it documented that lc() doesn't mind an undefined argument ?

I can't see it documented, but it is a common idiom when using CGI.pm to
use:

my $foo = lc(param('foo'));

for exactly the purpose you describe - supressing the undef warnings.

I am not a Perl internals hacker, but at a guess (and I am probably
wrong) this source looks relevant:

if (!len) {
SvUTF8_off(TARG); /* decontaminate */
sv_setpvn(TARG, "", 0);
SETs(TARG);
}

(perl 5.8.6 - pp.c lines 3587 - 3591)

HTH,
Steve
 
S

Stephen Hildrey

Paul said:
It could come back to bite you one day if: 1) a future release of Perl
suddenly introduces a Flag() function; 2) your code is modified to
include a Flag() subroutine; 3) your code is modified to import a
module which exports a Flag() subroutine; 4) your code is modified to
include a constant named Flag. If you're worried about one or more of
those, much safer to use the quotes.

Not true.

A simple expression (like a single token) inside the {} will
automatically be treated as quoted, so the following:

perl -w -MData::Dumper -e 'sub foo { return "bar"; } my %h; $h{foo} =
"baz"; print Dumper(\%h)'

will give the expected:

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

Similarly,

perl -w -MData::Dumper -e 'my %h; $h{print} = "baz"; print Dumper(\%h)'

will give the expected:

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

Obviously clarity is the priority and if it is unclear what is going on
then either quote it or include a comment.

As to the use of constants, perldoc constant says it more succinctly
than I can:

"You can get into trouble if you use constants in a context which
auto-matically quotes barewords (as is true for any subroutine call).
For example, you can't say $hash{CONSTANT} because "CONSTANT" will be
interpreted as a string. Use $hash{CONSTANT()} or $hash{+CONSTANT} to
prevent the bareword quoting mechanism from kicking in."

Steve
 
L

Len

Thanks for the thoughtful discussion. Just to clarify:
So the upshot is that the use of barewords as hash keys is a sound
and
recommended practice?

Cheers,
-Len
 
S

Stephen Hildrey

Thanks for the thoughtful discussion. Just to clarify:
So the upshot is that the use of barewords as hash keys is a sound
and
recommended practice?

It boils down to this: if your hash key is a bareword, you can leave out
the quotes; anything more complex as the key and Perl will interpret it
as an expression.

It's certainly a valid practice, whether it's sound and/or recommended
it probably a matter of taste. I'd argue "be consistent / be nice" here,
with a dose of "be understandable" :)

Steve
 
T

Tassilo v. Parseval

Also sprach Stephen Hildrey:
I can't see it documented, but it is a common idiom when using CGI.pm to
use:

my $foo = lc(param('foo'));

for exactly the purpose you describe - supressing the undef warnings.

I am not a Perl internals hacker, but at a guess (and I am probably
wrong) this source looks relevant:

if (!len) {
SvUTF8_off(TARG); /* decontaminate */
sv_setpvn(TARG, "", 0);
SETs(TARG);
}

(perl 5.8.6 - pp.c lines 3587 - 3591)

It's not really surprising that this behaviour is implemented somewhere
in the source. However, the code you quote is common in string handling
routines that usually upgrade undef to the empty string. The actual
check for emitting the warning normally happens before. But not in the
case of (uc|lc)(_first)? and possibly others for no apparent reason.

I'm inclined to say this is a bug unless someone is able to explain the
reasoning behind that behaviour.

Tassilo
 
C

ced

Tassilo said:
Also sprach Stephen Hildrey:


It's not really surprising that this behaviour is implemented somewhere
in the source. However, the code you quote is common in string handling
routines that usually upgrade undef to the empty string. The actual
check for emitting the warning normally happens before. But not in the
case of (uc|lc)(_first)? and possibly others for no apparent reason.

I'm inclined to say this is a bug unless someone is able to explain the
reasoning behind that behaviour.

I was starting to believe it might be a bug but string operators
(at least the ones below) behave like the string function 'uc'
as well:

# neither emit a warning
perl -wle 'my $foo;print $foo .""'
perl -wle 'my $foo;print $foo x 3'
 
T

Tassilo v. Parseval

Also sprach (e-mail address removed):
Tassilo v. Parseval wrote:

[ lc(undef) wont warn ]
I was starting to believe it might be a bug but string operators
(at least the ones below) behave like the string function 'uc'
as well:

# neither emit a warning
perl -wle 'my $foo;print $foo .""'
perl -wle 'my $foo;print $foo x 3'

This is a family of special cases. It also applies to numerical values:

my $a;
$a++; # never warns

The idea is to allow for something like this:

my $var;
while () {
...
$var .= $char;
}

without the need for any initial value for $var.

But I don't see how the functions mentioned in this thread fall into
this category. Meanwhile, I found one other builtin that wont warn on
undef: 'reverse' in scalar context.

What is worse about these cases is the fact that after applying any of
these functions, the value is no longer undef but the empty string. In a
context of a program these two values might have a very different
meaning and silently transforming one into the other is wrong.

Tassilo
 
A

Anno Siegel

Tassilo v. Parseval said:
Also sprach (e-mail address removed):
Tassilo v. Parseval wrote:
[...]

But I don't see how the functions mentioned in this thread fall into
this category. Meanwhile, I found one other builtin that wont warn on
undef: 'reverse' in scalar context.

What is worse about these cases is the fact that after applying any of
these functions, the value is no longer undef but the empty string. In a
context of a program these two values might have a very different
meaning and silently transforming one into the other is wrong.

That's only a consequence of some functions stringifying their argument,
the same goes for hash keys. I wouldn't worry about it, a programmer
doesn't expect a function like lc to return its argument unchanged. I think
it's just a missing "uninitialized" warning -- add that and reverse and
lc fit right in.

Anno
 
T

Tassilo v. Parseval

Also sprach Anno Siegel:
Tassilo v. Parseval said:
Also sprach (e-mail address removed):
Tassilo v. Parseval wrote:
[...]

But I don't see how the functions mentioned in this thread fall into
this category. Meanwhile, I found one other builtin that wont warn on
undef: 'reverse' in scalar context.

What is worse about these cases is the fact that after applying any of
these functions, the value is no longer undef but the empty string. In a
context of a program these two values might have a very different
meaning and silently transforming one into the other is wrong.

That's only a consequence of some functions stringifying their argument,
the same goes for hash keys. I wouldn't worry about it, a programmer
doesn't expect a function like lc to return its argument unchanged. I think
it's just a missing "uninitialized" warning -- add that and reverse and
lc fit right in.

Yes, I am not worried about the empty string that is produced but the
fact that it happens silently. When I get warnings about uninitialized
values it's almost always a bug in my programs. So that's a warning I
cannot do without.

Tassilo
 
L

Len

I have checked these results on various versions of Perl on
a couple different machines going back to v5.004_04 .

My results:

For ALL versions tested, there are NO warnings for:
perl -wle 'my $foo ;
print "\L$foo", lc $foo, uc $foo, ucfirst $foo, $foo x 1'

For ALL versions tested, there IS a warning for:
perl -wle 'my $foo ; print reverse $foo' ;

For ALL versions tested, EXCEPT v5.6.1 , there IS a warning for:
perl -wle 'my $foo ; print $foo . ""' ;

So I would be interested in what versions gave Charles and Tassilo
the results they reported:
Charles DeRykus:
# neither emit a warning
perl -wle 'my $foo;print $foo .""'

Tassilo v. Parseval:
Meanwhile, I found one other builtin that wont warn on
undef: 'reverse' in scalar context.

Cheers,
-Len
 
T

Tassilo v. Parseval

Also sprach (e-mail address removed):
I have checked these results on various versions of Perl on
a couple different machines going back to v5.004_04 .

My results:

For ALL versions tested, there are NO warnings for:
perl -wle 'my $foo ;
print "\L$foo", lc $foo, uc $foo, ucfirst $foo, $foo x 1'

For ALL versions tested, there IS a warning for:
perl -wle 'my $foo ; print reverse $foo' ;

I said reverse in scalar context. The above is list context. The warning
you get is for the uninitialized value that print receives. Try:

perl -wle 'print scalar reverse undef'
For ALL versions tested, EXCEPT v5.6.1 , there IS a warning for:
perl -wle 'my $foo ; print $foo . ""' ;

You don't get a warning for

$foo .= "";

This is the special case I mentioned.

Tassilo
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top