Does fetchrow_hashref return into a default value? - perl

I'm trying to write like:
my $q='select name as N from names';
my $sth=$dbh->prepare( $q ) ;
$sth->execute;
$test->{ $_->{N} } = 1 while $sth->fetchrow_hashref();
but $_ is undef. Does the return value get stored somewhere accessible without explicitly assigning it? Tim, it sure would be handy if it got stored somewhere!

The while loop does not always implicitly assign a value to the default operator $_. As described in perldoc perlsyn:
If the condition expression of a while statement is based on any of a
group of iterative expression types then it gets some magic treatment.
The affected iterative expression types are readline, the
input operator, readdir, glob, the globbing operator, and
each. If the condition expression is one of these expression types,
then the value yielded by the iterative operator will be implicitly
assigned to $_.
(...and otherwise it is not, is implied here)
To do what you want, you need to do
... while $_ = $sth->fetchrow_hashref();
Or better yet, use the idiomatic syntax:
while (my $row = $sth->fetchrow_hashref()) {
$test->{ $row->{N} } = 1;
}

Related

'=' is working in place of 'eq'

Hi I am writing a perl script to accomplish some task.In my script I am using one if loop to compare two strings as shown below.
if($feed_type eq "SE"){
...........}
The above code is not giving me any warning but the output is not as I expected.
Instead of 'eq' if I use '=' I am getting a warning saying expectng '==' but '=' is present. But I am getting the expected output.
Ideally for string comparison I must use 'eq' and for numbers '=='. In this case it's not working. Can anyone figure out what is the problem here?
More info:
This if loop is present in a subroutine. $feed_type is an input for this subroutine. I am reading the input as below:
my $feed_type=#_;
The problem is fixed. I just changed the assignemet statement of feed_type as below
my $feed_type=$_[0];
and it's reading the value as SE and the code is working.
but I still dont know why my $feed_type=$_[0]; didn't work.
= might well work in place of eq, but not for the reason you think.
#!/usr/bin/env perl
use strict;
use warnings;
my $test = "fish";
my $compare = "carrot";
if ( $test = $compare ) {
print "It worked\n";
}
Of course, the problem is - it'll always work, because you're testing the result of an assignment operation.*
* OK, sometimes assignment operations don't work - this is why some coding styles suggest testing if ( 2 == $result ) rather than the other way around.
This is about a core Perl concept: Context. Operators and functions work differently depending on context. In this case:
my $feed_type = #_;
You are assigning an array in scalar context to the variable. An array in scalar context returns its size, not the elements in it. For this assignment to work as you expect, you have to either directly access the scalar value you want, like you have suggested:
my $feed_type = $_[0];
...or you can put your variable in list context by adding parentheses:
my ($feed_type) = #_;
This has the benefit of allowing you to perform complex assignments, like this:
my ($first, $second, #rest) = #_;
So, in short, the problem was that your comparison that looked like this:
if($feed_type eq "SE")
Was actually doing this:
if(1 eq "SE")
And returning false. Which is true. Consider this self-documenting code:
sub foo {
my $size = #_;
if ($size == 1) {
warn "You passed 1 argument to 'foo'\n";
return;
}
}
Which demonstrates the functionality you inadvertently used.
= is used to assign the variable a value, so you would need '==' to compare numerical values and 'eq' for strings.
If it's complaining about not using '==', then it's because $feed_type is not a string.
I can't tell as there's no more code. Whatever $feed_type is set by you need to confirm it actually contains a string or if you're even referencing it correctly.

What is the definition of stringwise equality in Perl?

I was curious about the results of the following perl snippets:
my $var1 ;
my $var2 ;
if( $var1 eq $var2 ) {
print "yes";
} else {
print "no";
}
and
my $var1 ;
my $var2 = "";
if( $var1 eq $var2 ) {
print "yes";
} else {
print "no";
}
They turn out to be yes(Perl 5.16).
Unlike javascript specificaton, there is clear description of Equality Comparison Algorithm(http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3), the perl doc for Equality Operators says:
Binary "eq" returns true if the left argument is stringwise equal to the right argument.
But what is the definition of stringwise equality?
You're not having a problem with the definition of stringwise equality. What you don't seem to have wrapped your head arround yet is the concept of stringification. In this particular case, undef stringifies to ''.
Perl has monomorphic operators (mostly) and contextually polymorphic data types.
What this means is that it is the operator that dictates how the data is represented. The eq operator is for stringwise equality. The == operator is for numeric equality. When == is applied to strings, they are treated as numbers. When eq is applied to numbers, they are treated as strings. Each of these internal transformations follow a very specific set of rules.
Thus, when you apply a stringwise operator to a pair of values, those values will be treated as strings. When you apply a numeric operator to a pair of values, they will be treated as numbers.
In your second example, $var1 contains undef, and $var2 contains an empty string. When you compare $var1 eq $var2, the rules of stringification are applied to the operands. $var2 is already a string. But $var1 must be stringified before it can be compared. The rule of stringification for an undefined value is to treat it as an empty string. So $var1 eq $var2 is seen by the eq operator as '' eq '', which is to say, empty string eq empty string.
TRUE.
Note: In modern versions of Perl, using an undefined scalar variable in a stringwise operation only results in stringification for the duration of the operation; the underlying data in the container isn't altered. (see perldata).
perldata is one resource on this topic.
Your definition question has been answered by DavidO, but the (probably) most important piece of information is in TLP's comment - you should always use these two at the top of every script:
use strict;
use warnings;
The one relevant in this case is use warnings, which will produce the following warning:
Use of uninitialized value $var1 in string eq
Some programs go even further - this will cause the program to die because of this:
use warnings FATAL => 'all';
You are comparing variables using eq, which means you are doing a string comparison. A string comparison expects two strings, but you are providing an undefined variable (variable declared, but not defined, so not a string). This is not clean because you are using that operator with invalid input. If you wanted to know if the variables differ, not just the strings they (may or may not) represent, you would not use a string comparison like that.
It works because Perl knows that you want to compare strings (eq) so it assumes you don't care about the fact that a variable has no value assigned. The undefined variable is converted into an empty string (temporarily), which is then compared. (Actually, the variable itself isn't converted, it's still undef after the comparison, but that's not important.)
Of course, this assumption could be wrong and there might be a bug in your code. So it'd be better to check for invalid input before comparing it.
You don't care about the difference between undef and '' (and you know why).
You could explicitly compare empty strings instead of undef. Another programmer who is reading your code will know what's going on (won't assume there's a bug).
if (($var1 // q()) eq ($var2 // q()))
...
In many cases, you might actually care about undef.
For example, your script might take some input (maybe a hash) and if that input variable is an empty string, that would be okay, but if it's undef (maybe not found in the input hash), that would be an error.
if (!defined($var1))
{
die "Input data missing, can't continue!";
}
if ($var1 eq $var2)
...

Comparing empty string with number

I have a global value:
my $gPrevious ='';
# main();
func();
sub func {
my $localval = 52552;
if ($gPrevious != $localval) {
------------
x statements;
}
}
Output:
Argument "" isn't numeric in numeric ne (!=) at line x.
Why do I use the ne operator?
Here I am comparing with an empty string.
The value undef is there specifically so that you can test whether a variable has been defined yet. Initialising a variable to a string when it is to be compared to a number rather defeats this purpose.
You should leave your $gPrevious variable undefined, and test for that inside your subroutine.
Like this
my $gPrevious;
func();
sub func {
my $localval = 52552;
unless (defined $gPrevious and $gPrevious == $localval) {
# x statements;
}
}
Using the '==' or '!=' comparison operator requires having two numbers.
If one of the two is a string that perl can easily make a number such as "1", perl will do what you want and compare the 1.
But: If you compare a string or undef with the '!=' operator, there will be a warning.
In your case, I suggest you simply use
$gPrevious = 0;
# ...
if ( $gPrevious != $local_val ){ #...
which would get rid of the warning and work fine.
Testing for defined is another possibility, while testing for integers is not trivial.
You could use eq instead, but this is problematic, as then for example '1.0' ne '1'.
Perl provides two separate operators for string comparison (eq/ne) and numeric comparison (==/!=). LHS value must match the type of operator being used. In your case, LHS is a string and you are using a numeric operator for comparison. Hence, the error.

Why doesn't my subroutine return value get assigned to $_ default variable

I have a Perl subroutine which updates an RSS feed. I want to test the returned value, but the function is used in many places so I wanted to just test the default variable $_ which as far as I understand should be the assigned the return value if no variable is specified.
The code is a bit too long to include all of it, but in essence it does the following
sub updateFeed {
#....
if($error) {
return 0;
}
return 1;
}
Why then does
$rtn = updateFeed("My message");
if ($rtn < 1) { &Log("updateFeed Failed with error $rtn"); }
NOT log any error
whereas
updateFeed("myMessage");
if ($_ < 1) { &Log("updateFeed Failed with error $_"); }
logs an error of "updateFeed Failed with error"? (Note no value at the end of the message.)
Can anyone tell me why the default variable seems to contain an empty string or undef?
Because Perl doesn't work that way. $_ doesn't automatically get the result of functions called in void context. There are some built-in operators that read and write $_ and #_ by default, but your own subroutines will only do that if you write code to make it happen.
An ordinary function call is not one of the contexts in which $_ is used implicitly.
Here's what perldoc perlvar (as of v5.14.1) has to say about $_:
$_
The default input and pattern-searching space. The following pairs are equivalent:
while (<>) {...} # equivalent only in while!
while (defined($_ = <>)) {...}
/^Subject:/
$_ =~ /^Subject:/
tr/a-z/A-Z/
$_ =~ tr/a-z/A-Z/
chomp
chomp($_)
Here are the places where Perl will assume $_ even if you don't use it:
The following functions use $_ as a default argument:
abs, alarm, chomp, chop, chr, chroot, cos, defined, eval, exp, glob, hex, int, lc, lcfirst, length, log, lstat, mkdir, oct, ord, pos, print, quotemeta, readlink, readpipe, ref, require,
reverse (in scalar context only), rmdir, sin, split (on its second argument), sqrt, stat, study, uc, ucfirst, unlink, unpack.
All file tests (-f, -d) except for -t, which defaults to STDIN. See -X in perlfunc
The pattern matching operations m//, s/// and tr/// (aka y///) when used without an =~ operator.
The default iterator variable in a foreach loop if no other variable is supplied.
The implicit iterator variable in the grep() and map() functions.
The implicit variable of given().
The default place to put an input record when a <FH> operation's result is tested by itself as the sole criterion of a while test. Outside a while test, this will not happen.
As $_ is a global variable, this may lead in some cases to unwanted side-effects. As of perl 5.9.1, you can now use a lexical version of $_ by declaring it in a file or in a block with my.
Moreover, declaring our $_ restores the global $_ in the current scope.
Mnemonic: underline is understood in certain operations.
You never assigned the flag to $_, so why would it contain your flag? It appears to contain an empty string (or perhaps undef, which stringifies to the empty string with a warning).
$_ isn't by set by subroutines in void context by default. It is possible to write your subs to set $_ when is void context. You start by checking the value of wantarray, and set $_ when wantarray is undefined.
sub updateFeed {
...
my $return
...
if($error) {
$return = 0;
}else{
$return = 1;
}
# $return = !$error || 0;
if( defined wantarray ){ # scalar or list context
return $return;
}else{ # void context
$_ = $return;
}
}
I would recommend against doing this as it can be quite a surprise to someone that is using your subroutine. Which can make it harder to debug their program.
About the only time I would do this, is when emulating a built-in subroutine.

Can you explain the context dependent variable assignment in perl

The following is one of the many cool things that Perl can do
my ($tmp) = ($_=~ /^>(.*)/);
It finds the pattern ^>.* in the current line in a loop, and it stores the what's in the parenthesis in the $tmp variable.
What I am curious is the concept behind this syntax. How and why(under what premises) does this work?
My understanding is the snippet $_=~ /^>(.*)/ is a boolean context, but the parenthesis renders it as a list context? But how come only what is in the parenthesis in the matched pattern is stored in the variable?!
Is it some kind of special case of variable assignments I have to "memorize" or can this be perfectly explainable? if so, what is this feature called(name like "autovivifacation?")
There are two assignment operators: list assignment and scalar assignment. The choice is determined based on the LHS of the "=". (The two operators are covered in detail in here.)
In this case, a list assignment operator is used. The list assignment operator evaluates both of its operands in list context.
So what does $_=~ /^>(.*)/ do in list context? Quote perlop:
If the /g option is not used, m// in list context returns a list consisting of the subexpressions matched by the parentheses in the pattern, i.e., ($1, $2, $3...) [...] When there are no parentheses in the pattern, the return value is the list (1) for success. With or without parentheses, an empty list is returned upon failure.
In other words,
my ($match) = $_ =~ /^>(.*)/;
is equivalent to
my $match;
if ($_ =~ /^>(.*)/) {
$match = $1;
} else {
$match = undef;
}
Were the parens omitted (my $tmp = ...;), a scalar assignment would be used instead. The scalar assignment operator evaluates both of its operands in scalar context.
So what does $_=~ /^>(.*)/ do in scalar context? Quote perlop:
returns true if it succeeds, false if it fails.
In other words,
my $matched = $_ =~ /^>(.*)/;
is equivalent to
my $matched;
if ($_ =~ /^>(.*)/) {
$matched = 1; # !!1 if you want to be picky.
} else {
$matched = 0; # !!0 if you want to be picky.
}
The brackets in the search pattern make that a "group". What $_ =~ /regex/returns is an array of all the matching groups, so my ($tmp) grabs the first group into $tmp.
All operations in perl have a return value, including assignment. Thats why you can do $a=$b=1 and set $a to the result of $b=1.
You can use =~ in a boolean (well, scalar) context, but that's just because it returns an empty list / undef if there's no match, and that evaluates to false. Calling it in an array context returns an array, just like other context-sensitive functions can do using the wantarray method to determine context.