How does a function like OUTTRAP handle a STEM Variable name being passed to it as a string?
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Hobart Spitz
Actually you can do that only if you define a function with the same name as each stem you want to use that way..
Sorry. It would be nice if it worked that way, but the name spaces for stems and functions are completely separate. And the XXX.(...) syntax is a function call, not a stem reference.
Post by Steve Beaver
One rule -- Try it -- it might actually work
Sent: Wednesday, March 22, 2017 5:14 PM
Subject: Re: [TSO-REXX] Can I pass a stem to an internal subroutine?
I'll keep reading, but I've already learned something: I never knew I
could use expressions in a tail. Dunno why it never occurred to me to
That gives me "(stem.ja)+1", of course; I never thought to try
"stem.(ja+1)". Oh, well, that's how I keep from thinking I know everything.
/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */
Sent: Sunday, March 19, 2017 10:42
The short answer to the subject question is: Yes. Use VALUE(), period.
Like C/C++, REXX is a call-by-value language. This means that
subroutines and functions don't typically have any information about
passed variables besides their values; argument variables can't be
updated. (Most compiled mainframe languages are call-by-address, and
you don't have to do anything special to update an argument variable.)
To get around this, C/C++ use the & operator, which produces the
address of the specified variable. In REXX, it's analogous to pass
the quoted name of a variable or a stem to builtin functions such as VALUE() and SYMBOL().
As the original poster implied, you can use this technique, with
VALUE(), in a subroutine to get the similar functionality.
There is no reason to avoid the VALUE() function. There are many much
more expensive activities that will make VALUE() look like a single
grain of sand on a very large beach. These include garbage collection
(over which you have no control), and host commands, I/O, and the
invocation of external routines (about each of which you may have
little choice). In other words, the very slight overhead of VALUE(),
if any, is not worth worrying about.
There are reasons to use the VALUE() function: You can do some things
more succinctly (see the first example below). You can make routines
more generic and reusable. (See the second example below.)
Once you understand this, REXX becomes a much larger and more powerful
language. Some might say that you are not a REXXpert ( :-) ) unless
you know VALUE() and use it well. When I was more of a beginner, I,
too, did not appreciate VALUE().
It can be verbose to inspect stem elements when an tail expression is
involved. You can improve readability and avoid explicit temporary
variable assignments if you name a function the same as your stem.
(Yes, you can use a period in a label.)
Fred.0 = 3
Fred.1 = a
Fred.2 = b
Fred.3 = c
Eight = 8
say Fred.(Eight/4) /* Displays "B" or the value of B. */
Fred.0Tues = yes
say Fred.(0 || left(date("w"), 4), "newval") /* Displays YES on Tuesday,..
/* ..FRED.wkdy the rest of the week, perhaps, and sets the item to "newval". */
Fred.: /* Like value(), but for 1 stem. */
Item = "Fred."arg(1)
if arg(2, "e") then
return value(Item, arg(2))
You could generalize it, but then it's exactly the same a VALUE().
Since arrays implemented as stems require some housekeeping, I use a
routine like this to initialize a stem and/or add new elements.
OUTTRAP() and TSO PIPEs both support arrays implemented as numbered
scalars (without a period); similarly, Stem.Append() does not require the period.
call Stem.Append "Fred.", a, b, c
/* Add arg elements to stem implemented array. */
Tail = StemName || 0
LastItem = value(Tail)
/* Is StemName.0 initialized and valid? */
if \var(Tail) | \datatype(LastItem, "NUM") then do
LastItem = 0
if right(StemName, 1) = "." then
do iStemArg = 2 to arg()
LastItem = LastItem + 1
call value StemName || LastItem, arg(iStemArg)
call value Tail, LastItem
Var: return symbol(arg(1)) == "VAR" /* Like OS/2 var(). */
The VAR() shown here is just a convenience.
None of these routines use PROCEDURE. If you insist, you can code
PROCEDURE EXPOSE (GLOBALS) provided you set GLOBALS to the names of
the stems you are passing: Globals = "Loe. Carry. Murly." . Beware
of strange results if you forget. Or add Globals = Globals StemName
in the THEN clause of the first IF in Stem.Append().
If you have the TSO PIPE command, then you have options which go way
beyond native REXX. PIPE let's you directly access callers' variable
pools, including stems and their elements, for value, update, and drop.
You can completely avoid Stem.Append(), the stack, and pak()/hak()
type solutions using PIPE. TSO PIPEs are another whole dimension for REXX.
The underscore prefix is a good suggestion. I would advise that a
prefix of zero (0XYZ) would do the job just as well without having to
know what the convention means or paying a penalty for violating it.
The numeric prefix makes the variable name token into constant. Just
avoid values like 012E34, which are numbers.
I hope this helps.
--- On Sat, Mar 18, 2017 at 3:57 AM, Jeremy Nicoll <
Post by Jeremy Nicoll Post by Bob Bridges
I'm writing a program with an internal subroutine - well, I'd
~like~ to put the logic in a subroutine - that allows me to pass
the subroutine various stems and have it process whatever stem it
receives in a standard way.
You /can/ do that in ooREXX... which won't be a very helpful comment.
I used to achieve this sort of thing when calling external execs (as
when I wanted to pass one or more stems between them. My method did
use value(), and the pak/hak routines needed to be included in the
any exec / external function that used them. My method is unlikely to
any use if you're just wanting to use code within a single exec.
The basic idea is that if you have a stem array you can 'pak' it up
into one long string which can be 'hak'ed up (or unpacked) elsewhere.
The first version of this code (long ago) did actually use interpret
fred.1 = "horse"
fred.2 = ""
fred.3 = "cow"
fred.4 = "in the field"
fred.0 = 4
fredlong = pak("fred.")
The returned result ends up with a string comprising the number of
fields (in this case 4) and their lengths, then the actual text
"4 5 0 3 12 horsecowin the field"
This method (unlike some that some people post) has no problem with
elements of the array being empty, and does not require any specific
delimiter characters to mark out strings. The recipient could then do,
fredsize = hak("abc.",longtext)
which creates abc.1, abc.2, abc.3, abc.4 - I can't remember why the
original code didn't also set abc.0, but you can obviously do that with
abc.0 = hak("abc.",longtext)
temp.1 = pak("fred.")
temp.2 = pak("john.")
temp.3 = pak("mark.")
temp.0 = 3
and then of course you have two stages of haking to do.
parse arg stem ; numv = value(stem"0") num#vec = numv; txt#vec = ""
do token = 1 to numv; vartext = value(stem||token)
num#vec = num#vec length(vartext)
txt#vec = txt#vec || vartext
return num#vec txt#vec /* return value is packed string! */
parse arg stem, long
numv = subword(long,1,1); rest = subword(long,2)
do token = 1 to numv /* eg: numv = 1, rest = '5 abbot' or '5 bit' */
siz.token = word(rest,1) /* eg: '5' or '5' */
hak##chars = length(siz.token)
rest = substr(rest,hak##chars+2) /* eg: 'abbot' or ' bit' */
do token = 1 to numv
st = siz.token
assign = value(stem||token,substr(rest,1,st))
rest = substr(rest,st+1)
return numv /* return value is number of variables */
a) you can't readily make hak/pak functions into procedures unless
you know the names of the stem arrays in advance (so they can be
exposed explicitly). That means you should really make the
variables used in the pak/hak logic a bit more obscurely named.
b) you can make the routines more efficient - more statements per
line, creative use of parse rather than substr etc ... but I think
clarity is more important.
c) if you know things about the data being packed - eg if no element
is to be longer than 99 bytes, and there won't be any more elements
than 9999, you can store the first part of the packed string as
like: "0004 05 00 03 12 hor..." or even "000405000312 hor..." and
use substr to take it apart rather than subword - who knows if that
d) Rather than only storing the actual characters used in each
element in the text part of the packed string you might choose to
pad all elements to a fixed length, and then either hardcode hak to
substr that apart again without needing to know separate lengths
and/or pass the padded-element size back in the initial numbers.
"cat dog pig "
which would yield "cat ", "dog ", and "pig ". Clearly that
doesn't work if an arbitrary number of spaces needs to be preserved
on the end of each value, but knowing that each value is always 4
bytes long might speed-up the hak function.
e) Knowing that I'll have to pak() a stem array to pass it back to
the caller may well influence the design of that data structure's
contents in the first place.
f) I've used a variant of this in functions which could pass back
any number of stem arrays. A simple change to the packed text
pak("fred.") is (say) "fred. 4 5 0 3 12 horsecowin the field"
pak("john.") is "john. n ...."
etc means that you can have the called function dictate which arrays
the caller will get back. Usually I wouldn't recommend that because
a "rogue" called function could destroy the caller by returning an
array whose name clashes with something the caller uses themselves.
Also, it's possible to write more complex versions of 'pak' so that
stem element values are only stored once, and so on. I once wrote a
of compiler in rexx, as an external function, and it passed back a
set of paked stems (different types of call returned different
numbers of stems). I set this up so one of those stem contained
unique literal values and several of the others merely contained
indexes into that list of literals. In that particular application
some of the literals' values would otherwise have been stored many times.
For TSO-REXX subscribe / signoff / archive access instructions, send
For TSO-REXX subscribe / signoff / archive access instructions, send
For TSO-REXX subscribe / signoff / archive access instructions, send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX