Rexx Programming/How to Rexx/subroutine

From Wikibooks, open books for an open world
Jump to navigation Jump to search

"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[edit | edit source]

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[edit | edit source]

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[edit | edit source]

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[edit | edit source]

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[edit | edit source]

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[edit | edit source]

Subroutines can also call themselves and receive there 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.