Why does invoking print in a subroutine append 1 to the string?
I have created the following subroutine gender to randomly print string MALE or FEMALE. When subroutine is invoked, the print command suffixes a "1" at the end of the string. See the sa开发者_如何学Cmple code and output below:
sub gender {
if ( (int rand(100)) >50) {
print "MALE ";
}
else {
print "FEMALE";
}
}
foreach (1..5) {
print &gender, "\n";
}
Notice a "1" is suffixed to "MALE" OR "FEMALE"
OUTPUT:
FEMALE1
FEMALE1
MALE 1
MALE 1
FEMALE1
MALE 1
I am using perl v5.8.9 v5.8.9
built for MSWin32-x86-multi-thread
Binary build 826 [290470] provided by ActiveState http://www.ActiveState.com Built May 24 2009 09:21:05
print &gender
calls the gender function and prints what it returns. gender itself, as the last thing it does in either branch, prints a string. Implicitly, it returns the result of the last expression in it (the print "MALE" or print "FEMALE"), and print, when it succeeds, returns 1.
So either do this:
sub gender { if ( rand(100) >= 50 ) {print "MALE ";} else {print "FEMALE";}}
foreach (1..5) { &gender(); print "\n"; }
or this:
sub gender { if ( rand(100) >= 50 ) {return "MALE ";} else {return "FEMALE";}}
foreach (1..5) { print &gender(), "\n"; }
Also, note that &gender
, with & but without parentheses, is a special form of function invocation that isn't usually what people mean to use; either drop the & or add empty parentheses to your call.
I've also corrected the if test to return male 50% of the time and female 50% of the time, instead of 49% and 51% respectively.
Let's get idiomatic with your code:
print gender(), "\n"
for 1..5;
sub gender {
return int rand(100) > 50 ? 'MALE' : 'FEMALE';
}
So, what did I do?
First:
- The
gender
sub should not be called with the&
and no parens. This invokes the subroutine on the arguments passed to its caller. This is handy when you have a bunch of common argument sanitizing code. But it is not desirable or needed here. - I put the sub after the other code because I like to read my code from high level to specific--the opposite of how C forces you to organize things. I don't like reading my code from the bottom up, so I did it this way. This is purely a personal preference. Do whatever makes you happy. Or if you have to work with others, follow the standard you've agreed upon.
- I shortened
foreach
tofor
. They do exactly the same thing, one takes fewer characters. - I used
for
as a statement modifier. In other words I took a simple statementprint $_, "\n";
and tacked thefor
onto the end. For simple tasks it is nicer than using a block. Again, this is my opinion. Some people decry statement modifiers as evil and unwelcome. If you decide to use them, keep it simple. YMMV. - I got rid of the extra unneeded print ysth mentioned.
- Instead of using a big if/else block, I used the ternary operator (OK, it's really just a ternary operator, but people call it the ternary operator). It computes a test value and depending on the boolean value of the test, returns the result one of two expressions. It is handy when you want if/else logic in an assignment.
Without an explicit return
, the Perl sub will return the last evaluated value. gender
returns a 1 because in both execution paths, it calls print
which returns a 1.
You should either be having gender
return a string, which the caller then print
s, or have gender
do the printing, and have the caller not do anything with the return value.
Thank You everyone for helping me out with this. I found a way to make a chart I wanted. Here is how I finally did it;
print "GENDER NAME AGE HEIGHT WEIGHT \n";
foreach (1..10) { ## Starting foreach loop
$age = int(rand( 50))+10;
$height = int (rand(40)) + 50;
$weight = int (rand (100)) + 100;
sub randchar4bit {(chr int rand(25)+65).(chr int rand(25)+65). (chr int rand(25)+65).(chr int rand(25)+65)};
sub gender { return (int rand(100)>50)? "MALE " : "FEMALE ";} ;
print gender(), " ", &randchar4bit, " $age $height $weight style 1\n";
}; ## closing foreach loop
It generates a nice output:
GENDER NAME AGE HEIGHT WEIGHT
FEMALE HHRN 41 67 165 style 1
MALE HNMF 27 63 187 style 1
MALE NLDB 26 54 165 style 1
FEMALE REMB 33 71 118 style 1
MALE TWEW 10 57 122 style 1
MALE OCSC 35 80 168 style 1
FEMALE TKTR 25 64 179 style 1
MALE GMYN 47 73 123 style 1
MALE YKUG 50 79 148 style 1
FEMALE HDFW 47 73 159 style 1
精彩评论