![[Toc]](../../toc.gif)
![[Index]](/idx.gif)
New features in Object REXX that are useful in Classic REXX programs also
This section contains a list of some new features in Object-Oriented REXX
that are useful even for Classic REXX programs.
Please do not forget to check the version of the REXX interpreter you're
using with your REXX programs before you attempt to use on of these
features!
---------- * ----------
DO i OVER stem
This is a very useful enhancement of DO loops. Now you can simply walk
over all elements of a stem without knowing the tails:
/* drop all stem entries */
drop myStem.
do i = 1 to 40
j = random( 400 )
myStem.j = 1
end /* do i = 1 to 40 */
do i over myStem.
/* "i" contains the name of the next tail */
/* (to get the value use "myStem.i") */
say 'The ' || i || ' was at least one time set'
say 'The ' || myStem.i || ' was at least one time set'
end /* do i over myStem */
---------- * ----------
Returning a stem variable
In Object-Oriented REXX a routine can return a stem variable. Example:
/* */
test. = test1()
do i = 1 to test.0
say test.i
end
return
test1:
/* init a local stem ... */
a.0 = 3
a.1 = 11
a.2 = 22
a.3 = 33
/* ... and return it to the calling routine. */
return a.
---------- * ----------
Calculations and other stem variables are now possible to get or set a
stem variable. Example:
/* init a stem with sample values */
do i = 1 to 500;
test.i = i * 2
end /* do */
test.0 = 500
/* access the stem in the Classic way */
say test.5 /* (1) */
j = 4+55 /* (2) */
say test.j
i = test.4 /* (3) */
say test.i
i = test.4 /* (4) */
j = test.i
say test.j
/* use the new way */
say test.[5] /* (1) */
say test.[4+55] /* (2) */
say test.[test.4] /* (3) */
/* (4) */
say test.[test.[test.4]]
---------- * ----------
PARSE [upper|lower|caseless]
The PARSE instruction now supports lower and caseless parsing.
---------- * ----------
Call-by-Reference-Parameters are now possible for internal and external
REXX procedures (at least for stem variables):
/* */
say
say 'Sample code to show the usage of USE ARG in Object REXX '
say
j.0 = 2
j.1 = 111
j.2 = 222
say 'Values of the variables before calling the sub routine:'
say
say ' j.0 is ' || j.0
do k = 1 to j.0
say ' j.' || k || ' is ' || j.k
end /* do */
say
say 'Now calling TestUseArg ...'
say
call TestUseArg j.
say
say 'Values of the variables after calling the sub routine:'
say
say ' j.0 is ' || j.0
do k = 1 to j.0
say ' j.' || k || ' is ' || j.k
end /* do */
exit
TestUseArg: PROCEDURE
use arg local_j.
/* local_j points to the global stem j. */
local_j.0 = 3
local_j.1 = '111 - one'
local_j.2 = '222 - two'
local_j.3 = '333 - three'
return
---------- * ----------
<CALL now accepts variables that are evaluated before the CALL statement
is executed:
/* */
myRoutine = 'MYTEST'
call (myRoutine)
exit
MYTEST:
say 'This is mytest!'
RETURN
Plese note that the contents of the variable must be in uppercase if
calling an internal routine. This is not clearly stated in the online
help.
---------- * ----------
<DATE is not restricted to the current date any more. Now you can use the
results of this function for date calculations (e.g. How many days are
between day 1 and day 2?).
---------- * ----------
<STREAM now supports some more commands and options; for example FLUSH,
REPLACE (rewrite a file without doing a DEL first), and NOBUFFER. It also
supports line-related positioning for files with fixed and variable length
records. And there are now two different file pointers for every file --
one for reading from it and one for writing to it.
---------- * ----------
< TIME is not restricted to the current time any more. This allows
calculations with time stamps.
---------- * ----------
Use the environment .local for variables global to the current process.
Example:
/* create a variable global to the current process */
.local['BS.MYVAR'] = 'This is a global variable'
/* call an external REXX routine to show that it works */
call rexxtry "say .local['BS.MYVAR'] "
call rexxtry ".local['BS.MYVAR'] = 'This variable is set by REXXTRY'"
say .local['BS.MYVAR']
/* you can also use the following code to read the variable */
/* But be aware of the search order for environment symbols in */
/* Object REXX! */
say .BS.MYVAR
Note: "To avoid conflicts with future REXX-defined entries, it is
recommented that entries you place in the program local environment
or in the global environment include a least one period in the
entry name."
---------- * ----------
Use the environment .environment for variables global to all REXX
programs. Example:
/* create a variable global to all REXX programs */
.environment['BS.MYVAR'] = 'This is a global variable'
/* start a REXX program in another process to show that it works */
"cmd /c rexxtry say .environment['BS.MYVAR'] "
"cmd /c rexxtry .environment['BS.MYVAR'] = 'This variable is set by REXXTRY'"
say .environment['BS.MYVAR']
/* you can also use the following code to read or change the variable */
say value( 'BS.MYVAR',,'' )
call value 'BS.MYVAR', 'Value set using the VALUE function', ''
Note that the environment .environment contains a lot of default
variables that you should NOT change. To get a list of all existing
variables you can use the following code:
/* show all variables in the environment .environment */
do i over .environment
say 'Variable "' || i || '" is "' || .environment[i] || '"'
end /* do i over .envrionment */
To check if a variable is already defined, you can use the following
code:
/* check if a variables is defined in the environment .environment */
globalVar = 'BS.MYVAR'
if .environment[globalVar] = .NIL then
say 'Environment symbol "' || globalVar || '" is not defined.'
else
do
say 'Environment symbol "' || globalVar || '" is defined;'
say 'the value is "' || .environment[globalVar] || '".'
end /* else */
Note: "To avoid conflicts with future REXX-defined entries, it is
recommented that entries you place in the program local
environment or in the global environment include a least one
period in the entry name."
---------- * ----------
Use the directives ::REQUIRES and ::ROUTINE to implement external
routines.
---------- * ----------
Use the keyword instruction RAISE to raise a condition in the calling
routine. This is very handy to avoid endless return code evaluations.
Example:
/* ------------------------------------------------------------------ */
/* save this code in the file 'TEST1.CMD' */
parse source . . thisFile
say 'This is ' || thisFile || '.'
/* install an error handler for user condition 4 */
call on user 4 name ErrorRaised
say 'Now calling TEST2.CMD. TEST2.CMD will raise an user condition ...'
/* now call TEST2.CMD; test2.cmd will raise an */
/* user condition */
call TEST2.CMD
say 'Now ending the test program.'
exit
/* ------------------------------------------------------------------ */
/* simple handler for the user condition 4 */
ErrorRaised:
say
say '*** start of user condition handler ***'
say
say 'Condition "' || condition( 'C') || '" raised in line ' || ,
sigl || '.'
say 'The condition description is "' || condition( 'D' ) || '".'
say 'Additional information is "' || condition( 'A' ) || '".'
say
say '*** end of user condition handler ***'
say
return
/* ------------------------------------------------------------------ */
/* save this code to TEST2.CMD */
parse arg thisArgs
parse source . . thisFile
say ' This is "' || thisFile || '".'
say ' Called with "' || thisArgs || '".'
/* raise a user condition to the caller */
raise user 4 ,
Description 'This is a user error' ,
Additional 'This is additional information'
exit
/* ------------------------------------------------------------------ */
---------- * ----------
And there are a lot of very useful new functions in the REXXUTIL.DLL. See
New REXXUTIL functions in Object REXX for an overview of the new
functions. This section also contains information on how to use the new
REXXUTIL.DLL with Classic REXX.
Again, read the section <MIGRATION in the Online-Help of Object-Oriented
REXX -- else you might miss some of the new features.
Created using Inf-PHP v.2 (c) 2003 Yuri Prokushev
Created using Inf-HTML v.0.9b (c) 1995 Peter Childs