411 REFERENCE · Wikibooks
Rexx Programming/How to Rexx/subroutine
Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.
"Procedures" or "subroutines" are self-contained sections within the code that carry out specific tasks. They are small programs within the larger program. We can activate them within our code by using a CALL statement. A subroutine can signal that it has finished its task using a RETURN statement.
/* Call subroutines to make different animal noises. */
call BarkFiveTimes
call MeowThreeTimes
call MooEightTimes
exit
BarkFiveTimes:
do 5
say "Woof!"
end
return
MeowThreeTimes:
do 3
say "Meow!"
end
return
MooEightTimes:
do 8
say "Moo!"
end
return
Parsing arguments
Ideally, subroutines will be flexible enough to respond to various situations. We should be able to feed one or more pieces data into a subroutine to modify its behavior. These pieces of data are called "arguments", and you can include them within the CALL statement. They can be assigned to variables within the subroutine using a PARSE ARG statement.
/* Bark or meow as many times as you want. */
call Bark 5
call Meow 3
exit
Bark:
parse arg bark_count
do bark_count
say "Woof!"
end
return
Meow:
parse arg meow_count
do meow_count
say "Meow!"
end
return
Local variables
Since it's annoying to need different variable names for the same purpose in different subroutines, we can make a function totally self-contained by using the PROCEDURE keyword. It will have its own variables that won't conflict with other variables elsewhere in the program, even if they have the same name.
call Bark 5
call Meow 3
exit
Bark:
procedure
parse arg count
do count
say "Woof!"
end
return
Meow:
procedure
parse arg count
do count
say "Meow!"
end
return
Code reuse
Anytime you see the same kind of code emerging in different parts of your program, it's likely you have a single process that can be set aside in a procedure. That way, any mistakes can be corrected just once, in only one place.
/* Make any animal noise as many times as you want. */
call MakeNoise "Woof!", 5
call MakeNoise "Meow!", 3
call MakeNoise "Moo!", 8
exit
MakeNoise:
procedure
parse arg noise, count
do count
say noise
end
return
Return values
Not only can subroutines receive values from the part of the program that calls them, but they can send data back when they finish. The subroutine returns a piece of data by including it in the RETURN statement, after which it will be available in a variable called RESULT.
/* Use a subroutine to convert angle measures. */
say "Enter a number of degrees:"
pull number
call GetRadians number
say number "degrees is the same as" result "radians."
exit
GetRadians:
procedure
parse arg degrees
pi = 3.14159
return pi * degrees / 180
As a shortcut to calling the subroutine and accessing the result in two different statements, you can use the single-line notation using parentheses described in the function section of this book.
say "Enter a number of degrees:"
pull number
say number "degrees is the same as " GetRadians(number) "radians."
exit
By the way, if you would like the arguments to be capitalized when they enter a subroutine, or if you don't care about letter case because the arguments are numbers, you leave out the PARSE keyword.
GetRadians:
procedure
arg degrees
pi = 3.14159
return pi * degrees / 180
Exposed variables
If you want the procedure to be only partially self-contained, you can give it access to particular global variables using the EXPOSE keyword. This can be useful when you have some data that needs to be shared between different parts of the program.
/* Use the same value of pi to perform different circle computations. */
PI = 3.14159
call CircleArea 10
say "The area of a circle with radius 10 is" result"."
call Circumference 50
say "The circumference of a circle of diameter 50 is" result"."
exit
CircleArea:
procedure expose PI
arg radius
return PI * radius ** 2
Circumference:
procedure expose PI
arg diameter
return PI * diameter
Recursion
Subroutines can also call themselves and receive their own return values. The effect is similar to a loop and is useful if the subroutine needs to start over and try something again, perhaps with slightly different data, in order to complete its original task.
/* First 10 triangular numbers */
call ShowTriangulars 10
exit
ShowTriangulars:
procedure
arg how_many
if how_many > 0 then do
one_less = how_many - 1
call ShowTriangulars one_less
say Triangular(how_many)
end
return
Triangular:
procedure
arg which?
if which? > 1 then do
previous = which? - 1
return Triangular(previous) + which?
end
return 1
If you expect a function to repeat itself hundreds or thousands of times, you are likely better off to code a loop inside it. A program can crash if the same function calls itself too many times before returning.