views:

480

answers:

4

How can I resolve this case of Useless use of a variable in a void context?

For example:

  my $err = $soap_response->code, " ", $soap_response->string, "\n";
  return $err;

I get warnings like Useless use of a variable in a void context? Why? How can I resolve it ?

+16  A: 

I guess you wanted to concatenate the string pieces to form the entire error message, so you'll have to use the dot instead of comma:

my $err = $soap_response->code. " ". $soap_response->string. "\n";
codaddict
`"$$soap_response{code} $$soap_response{string}\n"`
ephemient
@ephemient: That is not at all the same thing as the original code. Method calls are not hash lookups (even if the method just does a hash lookup, it might change in the future).
cjm
@cjm Those aren't method calls, try it yourself. `$$_{key}` is `${$_}{key}` is `$_->{key}`, except that the latter is a little more work to interpolate into a string. `perl -e'$_ = {key=>1}; print $$_{key}, ${$_}{key}, $_->{key}'` ==> 111
ephemient
@ephemient, the point is that the original code in the OP *is* using method calls, not hash lookups.
friedo
@friedo @cjm Oh, I *totally* missed that. Waugh. `"${\scalar $soap_response->code} ${\scalar $soap_response->string}\n"` but that's actually pretty damn ugly.
ephemient
+14  A: 

In case you want to concatenate the arguments, use the "." operator or join:

my $err = $soap_response->code. " ". $soap_response->string. "\n";
my $err = join '', $soap_response->code, " ", $soap_response->string, "\n";

Next is why Perl gives you warnings.

You're assigning to a scalar variable $err, and the right-hand side of the assignment is evaluated in scalar context.

Binary "," is the comma operator. In scalar context it evaluates its left argument in void context, throws that value away, then evaluates its right argument in scalar context and returns that value.

Evaluating a variable or a constant and throwing that value away is useless. And perl warns you about this.

FYI: Another possible issue with your code:

my $err = $soap_response->code, " ", $soap_response->string, "\n";

The assignment has higher precedence so that is:

(my $err = $soap_response->code), " ", $soap_response->string, "\n";

See Perl operators and precedence and the Comma operator for more information.

eugene y
Great answer. But 'the right argument' is a bit ambiguous. Its assigning the wrong value and not the right one :). Try, perhaps, 'right-most' or 'final' or 'last' or something.
daotoad
I'd really like this answer better if it included mention of the concatenation operator as "this is what you meant".
darch
This is a better explanation of what went wrong, but codaddict has a better solution. `join` is just overkill here. What he really wanted was the concatenation operator, `.`.
cjm
I've taken the comments into consideration. thanks
eugene y
+3  A: 
my $err = join(' ', $soap_response->code, $soap_response->string) . "\n";

or, better IMO:

return sprintf "%s %s\n", $soap_response->code, $soap_response->string;

See perldoc -f join and perldoc -f sprintf perldoc perlop.

Regarding the warning, see perldoc perlop and this note on the comma operator.

Sinan Ünür
+1 for the sprintf version, which is the right way to do this IMO.
RET
A: 

The answer to the "why does this happen?" question is one of context.

You are assigning to a scalar variable ($err), so the right-hand side of the assignment is being evaluated in scalar context. In scalar context, a list of items evaluates to the last one:

my $foo = "bar", "baz", "quux"; 
# $foo now is "quux"

so your statement says "call response->code, throw it away, give me a space, throw it away, call response->string, throw it away, give me a newline, and assign that to $err".

It's not just that = is a higher precedence than ,; it's also the context in which the expression's evaluated. If you had been assigning to an array, or simply printing the result, you wouldn't have gotten the error; both of those are using list context. The solutions using join and sprintf are converting the list into a scalar, thereby eliminating the warning.

Joe McMahon
`perl -le 'my $foo = "bar", "baz", "quux"; print $foo'` # prints "bar"
eugene y
@Joe, actually your example is parsed as `(my $foo = "bar"), "baz", "quux"`. To get the effect you describe, you need to say `my $foo = ("bar", "baz", "quux")` You're right about the behavior of the comma operator, but wrong about the precedence.
friedo