bronto has asked for the wisdom of the Perl Monks concerning the following question:
Dear Fellow monks
I am writing a test script for a module (a class
actually), and I'm in doubt on how to check that a method
is returning a list of values (not a reference, not a
scalar: a plain old list)
Now, the only way to check this that comes into my mind
is to assign the return value to both a scalar and a list
and see if the assigned values are consistent. For example,
this scriptlet works as I expect:
use strict ;
use warnings ;
sub test { my @x = qw(test) ; return @x }
my $test = test() ;
my @test = test() ;
print ">>> $test\n" ;
print map "[$_]\n",@test ;
print $test == scalar(@test)? "Yepa!\n" : "Nope!\n" ;
I am wondering if there is a better way (i.e.: more
Perlish or more compact) to do the same job.
Please note that I would like to do this without
relying on extra modules, unless they are bundled with
Perl 5.6.1; I don't want make test to depend
on the presence of an optional module (other than those
required by my modules themselves).
Thanks for any advice
--bronto
# Another Perl edition of a song:
# The End, by The Beatles
END {
$you->take($love) eq $you->made($love) ;
}
Re: Did I get what I expected (an array)?
by arturo (Vicar) on Jul 16, 2002 at 16:13 UTC
|
One of the interesting things about Perl is that what a subroutine returns is determined by the context in which it is called:
#!/usr/bin/perl
use warnings;
use strict;
sub foo {
my @water = qw(heavy normal polluted);
@water;
}
my $bar = foo();
my @baz = foo();
print "Bar : $bar\n";
print "Baz : @baz\n";
with "bar", the interpreter sees that it's assigning the returned value to a scalar (the call is made in scalar context), so it gives you the size of the list it returned -- as a matter of fact, you'd get the same result with my $bar = scalar foo();, so your code isn't doing what you expect. With "baz", it sees that it's assigning the returned value to an array (list context), so it assigns the members of the list it's returning to the array. (BTW, this sort of behavior is changing radically in Perl 6). If your sub returns a scalar, and you assign it to an array, what you get is a one member array. So, to a large extent, you get what you ask for from the subroutine. Perl (v. 5, anyway =) just isn't the kind of language that tries to enforce the distinction you're looking to enforce.
By the way, you can check for the calling context within the subroutine with wantarray. HTH
I mistrust all systematizers and avoid them. The will to a system shows a lack of integrity -- F. Nietzsche | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Did I get what I expected (an array)?
by Abigail-II (Bishop) on Jul 16, 2002 at 15:58 UTC
|
I really do not understand what you are trying to do.
In your test program, you are getting 1 in
scalar context, and ("test") in list context.
And that's ok. Could you give an example of what in your
eyes in a failure?
Also, in your title, you suggest that you want the function
to return an array, but in the text, you talk about returning
a list. A list, and not a scalar. But this is very confusing.
First, a function can not return an array. A function returns
either a scalar, or a list. What it returns is determined by
the context, and the context alone. A scalar
will be returned in scalar context, and a list will be returned
in list context. The return @x in the test function
never returns an array - it returns a scalar in scalar context,
and a list (consisting of the elements of @x) in
list context.
BTW, what is your fear of modules?
Abigail | [reply] [Watch: Dir/Any] [d/l] [select] |
|
Ok, I'll try a better translation from my thoughts in
italian to a better english :-)
Maybe I should restate the question this way:
is it possible , and how, to distinguish if a
sub/method is returning a single scalar (
return
$this
, which my test script should consider wrong)
or a list (return ($this) or
return qw(a bunch of values)) or an array
(return @this) which my test script should
both consider good?
I'm writing a test script (one of those that
make test runs) that checks if a class of mine
or a subclass of it behaves like it should.
My check detects the case return @this
but fails on return qw(this list).
use strict ;
use warnings ;
sub test { return ('a','test') }
my $test = test() ;
my @test = test() ;
print ">>> $test\n" ;
print map "[$_]\n",@test ;
print $test == scalar(@test)? "Yepa!\n" : "Nope!\n" ;
This one fails:
$ perl test.pl
>>> test
[a]
[test]
Argument "test" isn't numeric in numeric eq (==) at test.pl line 11.
Nope!
(even if I consider test's return value ok for my
class...)
I hope I explained now. Do I?
Ciao! --bronto
# Another Perl edition of a song:
# The End, by The Beatles
END {
$you->take($love) eq $you->made($love) ;
}
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
return $this;
return ($this);
return (($this));
return ((($this)));
all mean the same. The do not differ just like there is no
difference between:
3 + 4;
(3 + 4);
(3) + (4);
((3) + (4));
As for
return @x;
that will return the number of elements of @x
in scalar context, and a list consisting of the elements
of @x in list context. Perl will never return
an array. You can check for yourself:
my @x = qw /foo bar baz/;
sub my_func {return @x};
(my_func) [1] .= "hello";
This gives a compile error:
Can't modify list slice in concatenation (.) or string
Note that it says "list slice". A list, not an array.
Abigail | [reply] [Watch: Dir/Any] [d/l] [select] |
|
Re: Did I get what I expected (an array)?
by broquaint (Abbot) on Jul 16, 2002 at 16:08 UTC
|
There's is essentially no difference between returning a one element list and a single scalar. However if you're returning an array (not list) and assigning to a scalar you'll get the length of the list (as opposed to the first element when returning a list). This is all do with the context in which the sub is called, so maybe you could take advantage of context e.g
use strict ;
use warnings ;
sub test {
return wantarray ? qw(test) : scalar @{[qw(test)]};
}
my $test = test() ;
my @test = test() ;
print ">>> $test\n" ;
print map "[$_]\n",@test ;
print $test == scalar(@test)? "Yepa!\n" : "Nope!\n" ;
__output__
>>> 1
[test]
Yepa!
If you ever start using modules for this sort of thing I highly recommend any of the Test modules and for context issues the marvellous Want.
HTH
_________ broquaint | [reply] [Watch: Dir/Any] [d/l] |
(Russ) Re: Did I get what I expected (an array)?
by Russ (Deacon) on Jul 16, 2002 at 16:11 UTC
|
Well, in your example, print $test == scalar(@test)?, you are not testing for what you probably think you are. :-)
When you return @x into scalar context, you get the number of elements in @x. (Aside: to return the "right thing" in whatever context the user called, use wantarray) So, your test will always work, because you are doing the same thing twice.
If you don't want a reference, test against ref. If you want to prove you only returned one value (or you returned > 1), assign to an array and test with scalar, as you are.
Perhaps you should ask, "Why do I care if I have a list/array vs a scalar value?" There is no difference between your example (returning one value) and return 'test' (also one value) (except, of course, your array will not return 'test' into scalar context...).
Does it really matter, as long as you get one or more correct values?
Russ
Brainbench 'Most Valuable Professional' for Perl | [reply] [Watch: Dir/Any] |
|
|