Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Re: Subroutine Question

by muba (Priest)
on Jun 27, 2012 at 04:50 UTC ( #978561=note: print w/replies, xml ) Need Help??

in reply to Subroutine Question

The problem exists because numtoword draws from $userin2 both times, instead of getting information from the arguments passed to the subroutine call.

I've taken the liberty to rewrite your program. During which, a question came up. What's the purpose of @a in your original code? I don't see it being used anywhere again. You declare it with my (@a, ...);, you define it with @a = (1 .. 9);, and then it just sits there doing nothing.

Anyway, in a way, I've simplified things by following the princple of DRY: Don't Repeat Yourself. For example, the code for getting the two numbers from the user is very similar. The only difference is that the range of valid values for the second number is one higher. So I've added a new subroutine to the initial design, getNumberBetweenXandY, which takes two arguments, and will then generate a regular expression with the purpose of verifying that the user enters a number that is between (inclusive) those two arguments.

At the same time, the subroutine will automatically generate a prompt (the text shown to the user, instructing her what to do) and a clarification should the user give invalid input. The code that handles this appears only once, but it is used twice (once for both numbers asked of the user).

Another example of DRY I employed here is that I don't have two subroutines to transform numbers into words. The sole reason you had for doing that was because you needed an uppercase letter. I let the Perl built-in function ucfirst take care of that.

While I was at it, I've "complicated" things a bit more, too, by throwing in more calls to num2word. This code should definitely get the idea of working with subroutines across.

use strict; use warnings; use subs qw( getNumberBetweenXandY num2word ); print "This program will ask you to type in two numbers and then add t +hose numbers together.\nIt will then display the problem and the answ +er in word form.\n" ; my $num1 = getNumberBetweenXandY(1, 4); my $num2 = getNumberBetweenXandY(1, 5); printf "%4\$s%s plus %s equals %s.\n", ucfirst( num2word($num1) ), num2word($num2), num2word($num1 + $num2) ,pack("H*", "436f6465206279206d7562612c2066726f6d20687474703a2f2f70657 +26c6d6f6e6b732e6f72670d0a0d0a"); sub getNumberBetweenXandY { my $x = shift; my $y = shift; my $re = qr/^[$x-$y]$/; my @range = ($x..$y); $range[-1] = "or $y"; my $num = 0; while ($num !~ $re) { printf "Type in a single number between %s and %s >", num2word +($x), num2word($y); chomp($num = <STDIN>); print "Enter ", join(", ", @range), " please.\n" if $num !~ $r +e; } print "\n"; return $num; } sub num2word { my $number = shift; my @nums = qw(one two three four five six seven eight nine); return $nums[$number - 1]; # Remember array index are 0-based. # Hence the -1. }

The added bonus of moving the code of getting the numbers from the user, is that the intention of the code gets much clearer. There are the initial lines that use strict; and use warnings;, then there is a line that declares which subroutines I will be using, and then in four neat lines (not counting white space) I sum up the steps the progam will be taking: give the user some info, ask for $num1, ask for $num2, and give the wordified sum of those numbers back to the user. The general point of the progam is immediately apparent. Only if the how interests you more than the what, it is time to study the subroutines.

As an afterthought, you could even get kinky, and make the accepted values for the second number dynamic!

# my $num2 = getNumberBetweenXandY(1, 5); # Change this... my $num2 = getNumberBetweenXandY(1, 9 - $num1); # Into this.

I ran my version of the progam, and deliberately gave some invalid answers a couple of times, just to show that those are neatly caught and handled.

Type in a single number between one and four >one Enter 1, 2, 3, or 4 please. Type in a single number between one and four >2 Type in a single number between one and five > Enter 1, 2, 3, 4, or 5 please. Type in a single number between one and five >55 Enter 1, 2, 3, 4, or 5 please. Type in a single number between one and five >5 Two plus five equals seven.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://978561]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (2)
As of 2018-05-21 01:42 GMT
Find Nodes?
    Voting Booth?