REXX Tips & Tricks, Version 2.80


Inf-HTML [About][Toc][Index] 0.9b (c) 1995 Peter Childs


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

---------- * ----------

<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. 
   

Inf-HTML End Run - Successful