Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Useless use of array element in void context

Reply
Thread Tools

Useless use of array element in void context

 
 
Marek
Guest
Posts: n/a
 
      06-10-2007


Hello all,


as a beginner, I am not sure, why I get this message "Useless use of
array element in void context". To illustrate I made a concentrated
excerpt of my larger perl project.

I need to compare two strings, which start with a different date, than
are coming numbers, which may or may not be different, and one line
finishes with a name. Whether the numbers are different in the string,
I made a split on white space, to compare them. Is there probably a
better way to compare two strings? In any case perl syntax check is
complaining about line 41 but is running fine. Really no idea why?

Thank you in advance


marek


#! /usr/bin/perl/

use warnings;
use strict;

my @out_lines = split(
/\n/,
'Mit, 16.05.2007 992.50 44284.40 2688 69.50
10110.90 Name1
Don, 17.05.2007 1148.90 44364.80 2707 69.50
10307.60 Name2
Fre, 18.05.2007 1408.50 44496.50 2714 69.50
10512.90 Name1
Sam, 19.05.2007 1736.60 44665.00 2738 69.50
10864.50 Name2
Son, 20.05.2007 2003.41 44769.00 2746 69.50
11037.70 Name1
Mon, 21.05.2007 2294.10 44907.40 2754 70.50
11256.30 Name1
Die, 22.05.2007 2683.10 45151.10 2762 70.50
11607.90 Name1
Mit, 23.05.2007 2994.30 45284.10 2765 70.50
11808.00 Name1
Don, 24.05.2007 3092.10 45336.50 2777 70.50
11953.40 Name1
Fre, 25.05.2007 3092.10 45336.50 2777 70.50
11953.40 Name2
Sam, 26.05.2007 3092.10 45336.50 2777 70.50
11953.40 Name2
Son, 27.05.2007 3092.10 45336.50 2777 70.50
11953.40 Name2
Mon, 28.05.2007 3494.70 45498.30 2816 70.50
12358.30 Name2
Die, 29.05.2007 3896.20 45617.80 2821 70.50
12535.40 Name1
Mit, 30.05.2007 4226.30 45851.00 2829 70.50
12875.60 Name1
Don, 31.05.2007 4465.80 45920.90 2834 70.50
12974.20 Name1'
);

my $old_line;
foreach my $out_line (@out_lines) {
if ($old_line) {
$old_line =~ s/\s+[-a-z\d]+$//i;
my @old_line = split( /\s+/, $old_line );
my @out_line = split( /\s+/, $out_line );
if (
(
$old_line[2], $old_line[3], $old_line[4],
$old_line[5], $old_line[6]
) == (
$out_line[2], $out_line[3], $out_line[4],
$out_line[5], $out_line[6]
)
)
{
print "same numbers:\n";
print join("\t",@old_line) . "\n";
print join("\t",@out_line) . "\n";
print "TOTAL\t\t0.00\t0.00\t0.00\t0.00\t0.00\n";
}
else {
my $result2 = $out_line[2] - $old_line[2];
my $result3 = $out_line[3] - $old_line[3];
my $result4 = $out_line[4] - $old_line[4];
my $result5 = $out_line[5] - $old_line[5];
my $result6 = $out_line[6] - $old_line[6];
print "different numbers\n";
print join("\t",@old_line) . "\n";
print join("\t",@out_line) . "\n";
printf( "TOTAL\t\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",
$result2, $result3, $result4, $result5, $result6 );
}
$old_line = $out_line;
}
else {
$old_line = $out_line;
}
}

 
Reply With Quote
 
 
 
 
Peter J. Holzer
Guest
Posts: n/a
 
      06-10-2007
On 2007-06-10 10:20, Marek <(E-Mail Removed)> wrote:
> as a beginner, I am not sure, why I get this message "Useless use of
> array element in void context". To illustrate I made a concentrated
> excerpt of my larger perl project.
>
> I need to compare two strings, which start with a different date, than
> are coming numbers, which may or may not be different, and one line
> finishes with a name. Whether the numbers are different in the string,
> I made a split on white space, to compare them.


You cannot compare lists with "==". If you write something like

> if (
> (
> $old_line[2], $old_line[3], $old_line[4],
> $old_line[5], $old_line[6]
> ) == (
> $out_line[2], $out_line[3], $out_line[4],
> $out_line[5], $out_line[6]
> )
> )


the commas are interpreted as the comma operator, so it means something
like:

evaluate $old_line[2] and throw the value away, then
evaluate $old_line[3] and throw the value away, then
evaluate $old_line[4] and throw the value away, then
evaluate $old_line[5] and throw the value away, then
evaluate $old_line[6] and keep it,
evaluate $out_line[2] and throw the value away, then
evaluate $out_line[3] and throw the value away, then
evaluate $out_line[4] and throw the value away, then
evaluate $out_line[5] and throw the value away, then
evaluate $out_line[6] and keep it
if the two values we kept ($old_line[6] and $out_line[6] are
numerically equal ...

Or in other words, since there are no side effects, its exactly the same
as if you had written

if ($old_line[6] == $out_line[6])

Perl is warning you that this is probably not what you wanted.

What you probably wanted is to compare each field individually:

if ($old_line[2] == $out_line[2]
&& $old_line[3] == $out_line[3]
&& $old_line[4] == $out_line[4]
&& $old_line[5] == $out_line[5]
&& $old_line[6] == $out_line[6])

or in a loop:

my $same = 1;
$same = $same && $old_line[$_] == $out_line[$_] for (2 .. 6);
if ($same)


> Is there probably a better way to compare two strings? In any case
> perl syntax check is


This is not a syntax check. The syntax is fine. It is the semantic of
the code which is probably wrong.

> complaining about line 41 but is running fine.


Define "running fine". Are the results correct?

hp

--
_ | Peter J. Holzer | I know I'd be respectful of a pirate
|_|_) | Sysadmin WSR | with an emu on his shoulder.
| | | http://www.velocityreviews.com/forums/(E-Mail Removed) |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
 
Reply With Quote
 
 
 
 
Dr.Ruud
Guest
Posts: n/a
 
      06-10-2007
Marek schreef:

> if (
> (
> $old_line[2], $old_line[3], $old_line[4],
> $old_line[5], $old_line[6]
> ) == (
> $out_line[2], $out_line[3], $out_line[4],
> $out_line[5], $out_line[6]
> )
> )


This doesn't do what you expect it to. Test with

perl -wle 'print( (1,2,0) == (5,4,0) ? "A" : "B")'


Maybe use:

if ( join ( "\n", @old_line[2..6] ) eq
join ( "\n", @out_line[2..6] )
) {
...
}

but consider List::Util.


> my $result2 = $out_line[2] - $old_line[2];
> my $result3 = $out_line[3] - $old_line[3];
> my $result4 = $out_line[4] - $old_line[4];
> my $result5 = $out_line[5] - $old_line[5];
> my $result6 = $out_line[6] - $old_line[6];


Alternative-1:
$result[$_] = $out_line[$_] - $old_line[$_] for 2..6;

Alternative-2:
@result = map $out_line[$_] - $old_line[$_], 2..6;

> printf( "TOTAL\t\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",
> $result2, $result3, $result4, $result5, $result6 );


printf ( "TOTAL\t\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",
@result [2..6] );

or even:
my $s;
$s .= sprintf ( "\t%.2f", $out_line[$_] - $old_line[$_] )
for 2..6;
print "TOTAL\t", $s, "\n";

or evener:
my @s = '', map sprintf ( "%.2f", $out_line[$_] - $old_line[$_] ),
2..6;
print do { local $" = "\t"; "TOTAL$\"@s\n" };

--
Affijn, Ruud

"Gewoon is een tijger."

 
Reply With Quote
 
Paul Lalli
Guest
Posts: n/a
 
      06-10-2007
On Jun 10, 6:20 am, Marek <(E-Mail Removed)> wrote:
> as a beginner, I am not sure, why I get this message "Useless use
> of array element in void context". To illustrate I made a
> concentrated excerpt of my larger perl project.


Excellent! Well done! Seriously, that's one of the best things I've
read in this newsgroup in a long time.

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


More excellencence!!

> if (
> (
> $old_line[2], $old_line[3], $old_line[4],
> $old_line[5], $old_line[6]
> ) == (
> $out_line[2], $out_line[3], $out_line[4],
> $out_line[5], $out_line[6]
> )
> )
> {


This is the problem. This block does not do what you think it does.
The == operator in Perl does not compare lists. It only compares
scalars. Therefore, both of the "lists" are being evaluated in scalar
context[1], and so it's only comparing the last element of each list.
That is, the above block is identical to:
if ($old_line[6] == $out_line[6])
None of the other elements are being looked at by the == operator.
That's why Perl is telling you all those array elements are being
uselessly used in a void context.

If you want to compare two arrays for equality of their elements, you
have a few possibilities. You could modify the example in the FAQ to
suit your needs. (From a command line, run `perldoc -q equal`), or you
could use either of the modules Array::Compare or List::Compare from
the CPAN (head to http://search.cpan.org and search for those
modules).

Note there are also less robust solutions involving comparing the two
arrays as strings - for example:
if ("@a1" eq "@a2")
or
use Data:umper;
if (Dumper(\@a1) eq Dumper(\@a2) )
But these are generally dangerous because they could return false
positives. For example, the first one would report that these two
arrays are indeed equal:
my @a1 = (1, 2, 3);
my @a2 = ("1 2", 3);
The Dumper one is more unlikely to give false positives, but still
possible.

My overall suggestion would be to modify the example given in the FAQ
to suit your needs.

Good luck!
Paul Lalli

 
Reply With Quote
 
Paul Lalli
Guest
Posts: n/a
 
      06-10-2007
On Jun 10, 8:01 am, Paul Lalli <(E-Mail Removed)> wrote:
> The == operator in Perl does not compare lists. It only compares
> scalars. Therefore, both of the "lists" are being evaluated in
> scalar context[1]


Whoops, forgot my footnote. I meant to include the point that when
code looks as though a list is being used in a scalar context, what's
actually happening is that the comma operator is being used in scalar
context. The comma operator in scalar context does not create a list
- instead it evaluates its left argument, throws it away, and then
evaluates its right argument, and returns it.

my $x = (f1(), f2());
That statement calls the subroutine f1(), ignores its return value,
then calls f2() and puts f2's return value in $x.

So when you get a bunch of comma operators used in sequence like:
my $x = (1, 2, 3, 4, 5);
each comma operator evaluates its left argument, and then throws the
value away. The last element in the sequence (in this case, 5) is
returned from the expression. That's why
if ( (1, 2, 3) == (4, 5, 6) )
is only checking if 3 is equal to 6, and not any of the others.

Paul Lalli

 
Reply With Quote
 
Paul Lalli
Guest
Posts: n/a
 
      06-10-2007
On Jun 10, 7:50 am, "Dr.Ruud" <(E-Mail Removed)> wrote:
> Marek schreef:
>
> > if (
> > (
> > $old_line[2], $old_line[3], $old_line[4],
> > $old_line[5], $old_line[6]
> > ) == (
> > $out_line[2], $out_line[3], $out_line[4],
> > $out_line[5], $out_line[6]
> > )
> > )

>
> This doesn't do what you expect it to. Test with
>
> perl -wle 'print( (1,2,0) == (5,4,0) ? "A" : "B")'
>
> Maybe use:
>
> if ( join ( "\n", @old_line[2..6] ) eq
> join ( "\n", @out_line[2..6] )
> ) {
> ...
> }


So long as you're aware of the possibility of false positives, like:
my @a1 = (1, 2, 3);
my @a2 = ("1\n2", 3);

If that's not possible for your data, then by all means, go for it.

> but consider List::Util.


Can you explain which of List::Util's subroutines you believe will be
useful for comparing two lists for equality? Maybe reduce(), but if
so, I can't figure it out...


Thanks,
Paul Lalli

 
Reply With Quote
 
Dr.Ruud
Guest
Posts: n/a
 
      06-10-2007
Paul Lalli schreef:
> Dr.Ruud:


>> if ( join ( "\n", @old_line[2..6] ) eq
>> join ( "\n", @out_line[2..6] ) ) {

>
> So long as you're aware of the possibility of false positives, like:
> my @a1 = (1, 2, 3);
> my @a2 = ("1\n2", 3);
> If that's not possible for your data, then by all means, go for it.


Because the data was split on whitespace, as it often is, the
"technique" is possible.
It might remind some people of hoops they needed to go through when
using sed.

I don't tolerate such code in production, for the reason that you
mentioned, and for the data conversion (list values concatenated in a
string).


>> but consider List::Util.

>
> Can you explain which of List::Util's subroutines you believe will be
> useful for comparing two lists for equality? Maybe reduce(), but if
> so, I can't figure it out...


I now checked List::MoreUtils as well, and even that doesn't have the
compare functionality that I expected. I must have seen it someweher
else, Bit::Vector maybe.
Though List::MoreUtils:airwise can be used. But no list_is() or
list_eq() in either. Even a list_diff() would do.

Some other approaches:

if (5 == grep $_, map $old_line[$_] == $out_line[$_], 2..6) {
(but that needs two changes if the length of the range is changed)

my $same = 1; $same &&= $old_line[$_] == $out_line[$_] for 2..6;
(almost as hp showed)

unless (grep $_, map $old_line[$_] != $out_line[$_], 2..6) {
(ok, but not shortcutting)

my $diff; $diff ||= $old_line[$_] != $out_line[$_] and last for 2..6;
(shortcuts)



An (alpha) firstidx_diff for List::MoreUtils:
(beware, this one does numeric equation only)

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

sub firstidx_diff (\@\@;@) {
$_[0]->[$_] != $_[1]->[$_] and return $_
for $_[2] ? @_[2..$#_] : $[..$#{$_[0]};
return '==';
}

my @x = (0..6, 70..99);
my @y = (0..6, 80..99);
print firstidx_diff( @x, @y ), "\n"; # 7

my @x1 = @x[2..6];
my @y1 = @y[2..6];
print firstidx_diff( @x1, @y1 ), "\n"; # ==
print firstidx_diff( @x, @y, 2..6 ), "\n"; # ==

my @z = (9, 9, 2..6, 90..99);
print firstidx_diff( @x, @z ), "\n"; # 0
print firstidx_diff( @x, @z, 2..10 ), "\n"; # 7
__END__


P.S. Perl6::Junction?

--
Affijn, Ruud

"Gewoon is een tijger."

 
Reply With Quote
 
Peter J. Holzer
Guest
Posts: n/a
 
      06-10-2007
On 2007-06-10 15:50, Dr.Ruud <(E-Mail Removed)> wrote:
> Paul Lalli schreef:
>> Dr.Ruud:
>>> but consider List::Util.

>>
>> Can you explain which of List::Util's subroutines you believe will be
>> useful for comparing two lists for equality? Maybe reduce(), but if
>> so, I can't figure it out...

>
> I now checked List::MoreUtils as well, and even that doesn't have the
> compare functionality that I expected. I must have seen it someweher
> else, Bit::Vector maybe.


Test::More has is_deeply(). Maybe you were thinking of that.

hp

--
_ | Peter J. Holzer | I know I'd be respectful of a pirate
|_|_) | Sysadmin WSR | with an emu on his shoulder.
| | | (E-Mail Removed) |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
 
Reply With Quote
 
Mark Clements
Guest
Posts: n/a
 
      06-10-2007
Peter J. Holzer wrote:
> On 2007-06-10 15:50, Dr.Ruud <(E-Mail Removed)> wrote:
>> Paul Lalli schreef:
>>> Dr.Ruud:
>>>> but consider List::Util.
>>> Can you explain which of List::Util's subroutines you believe will be
>>> useful for comparing two lists for equality? Maybe reduce(), but if
>>> so, I can't figure it out...

>> I now checked List::MoreUtils as well, and even that doesn't have the
>> compare functionality that I expected. I must have seen it someweher
>> else, Bit::Vector maybe.

>
> Test::More has is_deeply(). Maybe you were thinking of that.


I've used Set::Array in the past for such comparisons, but YMMV

Mark
 
Reply With Quote
 
Dr.Ruud
Guest
Posts: n/a
 
      06-11-2007
Mark Clements schreef:
> Peter J. Holzer:
>> Dr.Ruud:
>>> Paul Lalli:
>>>> Dr.Ruud:


>>>>> but consider List::Util.
>>>>
>>>> Can you explain which of List::Util's subroutines you believe will
>>>> be useful for comparing two lists for equality? Maybe reduce(),
>>>> but if so, I can't figure it out...
>>>
>>> I now checked List::MoreUtils as well, and even that doesn't have
>>> the compare functionality that I expected. I must have seen it
>>> someweher else, Bit::Vector maybe.

>>
>> Test::More has is_deeply(). Maybe you were thinking of that.

>
> I've used Set::Array in the past for such comparisons, but YMMV


I assume that one ignores order, which wasn't OP's goal.

--
Affijn, Ruud

"Gewoon is een tijger."
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
not sure why I am getting the following warning "Useless use of aconstant in void context" mcardeiro@yahoo.com Perl Misc 7 12-15-2007 09:15 PM
syntax error warning: useless use of a variable in void context Tom Reilly Ruby 5 11-24-2005 04:05 AM
Useless use of a constant in void context makko Perl Misc 2 09-19-2005 01:18 PM
Useless use of private variable in void context at parser.cgi line 48. jon rogers Perl Misc 3 12-04-2003 12:21 AM
Useless use of private variable in void context ... ? George R. Gonzalez Perl Misc 1 08-08-2003 06:47 PM



Advertisments