Discussion:
Can I pass a stem to an internal subroutine?
(too old to reply)
Bob Bridges
2017-03-16 00:01:30 UTC
Permalink
Raw Message
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. But
so far I'm not doing very well. Maybe I'm just doing it wrong. Here's what
I'm attempting:

/* main routine */
call outtrap 'TSS.'
TSO command here<
call outtrap 'OFF'
say 'Outside' tss.1
call sub tss.
...
/* sub routine */
sub:
arg stem
say 'Inside' stem.
say 'Inside' stem.1
say 'Inside' stem.1
return

I get back something like this:

Outside <contents of tss.1>
Inside TSS.
Inside TSS.
Inside TSS.

I can get around this by using the VALUE function inside the routine, but
I'd rather not. Is there another syntax that works better? Anyone know?

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Horacio Villa
2017-03-16 00:18:06 UTC
Permalink
Raw Message
Hi Bob,

this worked for me:
/* REXX */
l.1 = 1
l.2 = 2
l.3 = 'r'
l.0 = 3
call listL 'l.'
exit
listL:
parse arg stem
say value(stem||1)
say value(stem||2)
say value(stem||0)
return

Horacio Villa
DB2 z/OS DBA Support, Database Administration
IBM Certified DataBase Administrator ? DB2 9 DBA for z/OS
IBM Corporation
( 5070-3443 / tl 840-3443 cell 15 6178-8908
* ***@ar.ibm.com






From: Bob Bridges <***@GMAIL.COM>
To: TSO-***@VM.MARIST.EDU
Date: 03/15/2017 09:01 PM
Subject: [TSO-REXX] Can I pass a stem to an internal subroutine?
Sent by: TSO REXX Discussion List <TSO-***@VM.MARIST.EDU>



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. But
so far I'm not doing very well. Maybe I'm just doing it wrong. Here's
what
I'm attempting:

/* main routine */
call outtrap 'TSS.'
TSO command here<
call outtrap 'OFF'
say 'Outside' tss.1
call sub tss.
...
/* sub routine */
sub:
arg stem
say 'Inside' stem.
say 'Inside' stem.1
say 'Inside' stem.1
return

I get back something like this:

Outside <contents of tss.1>
Inside TSS.
Inside TSS.
Inside TSS.

I can get around this by using the VALUE function inside the routine, but
I'd rather not. Is there another syntax that works better? Anyone know?

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX






----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Steve Beaver
2017-03-16 00:22:43 UTC
Permalink
Raw Message
Suggestion>

Drop comm.

Call xxx or

Irc = xxx(1)

PROCEDURE xxxxx EXPOSE COMM.



-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of
Horacio Villa
Sent: Wednesday, March 15, 2017 7:18 PM
To: TSO-***@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Can I pass a stem to an internal subroutine?

Hi Bob,

this worked for me:
/* REXX */
l.1 = 1
l.2 = 2
l.3 = 'r'
l.0 = 3
call listL 'l.'
exit
listL:
parse arg stem
say value(stem||1)
say value(stem||2)
say value(stem||0)
return

Horacio Villa
DB2 z/OS DBA Support, Database Administration IBM Certified DataBase
Administrator ? DB2 9 DBA for z/OS IBM Corporation ( 5070-3443 / tl 840-3443
cell 15 6178-8908
* ***@ar.ibm.com






From: Bob Bridges <***@GMAIL.COM>
To: TSO-***@VM.MARIST.EDU
Date: 03/15/2017 09:01 PM
Subject: [TSO-REXX] Can I pass a stem to an internal subroutine?
Sent by: TSO REXX Discussion List <TSO-***@VM.MARIST.EDU>



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. But
so far I'm not doing very well. Maybe I'm just doing it wrong. Here's
what
I'm attempting:

/* main routine */
call outtrap 'TSS.'
TSO command here<
call outtrap 'OFF'
say 'Outside' tss.1
call sub tss.
...
/* sub routine */
sub:
arg stem
say 'Inside' stem.
say 'Inside' stem.1
say 'Inside' stem.1
return

I get back something like this:

Outside <contents of tss.1>
Inside TSS.
Inside TSS.
Inside TSS.

I can get around this by using the VALUE function inside the routine, but
I'd rather not. Is there another syntax that works better? Anyone know?

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX






----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-16 01:10:38 UTC
Permalink
Raw Message
Post by Horacio Villa
say value(stem||1)
I believe he said he wanted to avoid using "value()"
Post by Horacio Villa
From: Bob Bridges
Date: 03/15/2017 09:01 PM
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. But
so far I'm not doing very well. Maybe I'm just doing it wrong. Here's what
/* main routine */
call outtrap 'STEM.A.'
TSO command here<
call outtrap 'OFF'
say 'Outside' stem.A.1
call sub 'A'
...
/* sub routine */
arg Q
say 'Inside' stem.Q.1
return
But you can't DROP part of a compound, if that's desired.
Post by Horacio Villa
I can get around this by using the VALUE function inside the routine, but
I'd rather not. Is there another syntax that works better? Anyone know?
I'm not sure what your objective is nor why you want to avoid value().
You might also conceal the stem with a "procedure", but then it wouldn't
be accessible in outer procedures.

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Horacio Villa
2017-03-16 01:53:20 UTC
Permalink
Raw Message
And I believe I answered before reading all of the mail!

Horacio




From: Paul Gilmartin <***@AIM.COM>
To: TSO-***@VM.MARIST.EDU
Date: 03/15/2017 10:12 PM
Subject: Re: [TSO-REXX] Can I pass a stem to an internal
subroutine?
Post by Horacio Villa
say value(stem||1)
I believe he said he wanted to avoid using "value()"
Post by Horacio Villa
From: Bob Bridges
Date: 03/15/2017 09:01 PM
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. But
so far I'm not doing very well. Maybe I'm just doing it wrong. Here's what
/* main routine */
call outtrap 'STEM.A.'
TSO command here<
call outtrap 'OFF'
say 'Outside' stem.A.1
call sub 'A'
...
/* sub routine */
arg Q
say 'Inside' stem.Q.1
return
But you can't DROP part of a compound, if that's desired.
Post by Horacio Villa
I can get around this by using the VALUE function inside the routine, but
I'd rather not. Is there another syntax that works better? Anyone know?
I'm not sure what your objective is nor why you want to avoid value().
You might also conceal the stem with a "procedure", but then it wouldn't
be accessible in outer procedures.

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX






----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Itschak Mugzach
2017-03-16 06:11:17 UTC
Permalink
Raw Message
If both main and sub uses same name, there is not problem. If using external subroutine
, I use to stack the array and by using queued() to rebuild it in sub.

ITschak

נשלח מה-iPad שלי
Post by Horacio Villa
And I believe I answered before reading all of the mail!
Horacio
Date: 03/15/2017 10:12 PM
Subject: Re: [TSO-REXX] Can I pass a stem to an internal
subroutine?
Post by Horacio Villa
say value(stem||1)
I believe he said he wanted to avoid using "value()"
Post by Horacio Villa
From: Bob Bridges
Date: 03/15/2017 09:01 PM
I'm writing a program with an internal subroutine - well, I'd ~like~ to
put
Post by Horacio Villa
the logic in a subroutine - that allows me to pass the subroutine
various
Post by Horacio Villa
stems and have it process whatever stem it receives in a standard way.
But
Post by Horacio Villa
so far I'm not doing very well. Maybe I'm just doing it wrong. Here's what
/* main routine */
call outtrap 'STEM.A.'
TSO command here<
call outtrap 'OFF'
say 'Outside' stem.A.1
call sub 'A'
...
/* sub routine */
arg Q
say 'Inside' stem.Q.1
return
But you can't DROP part of a compound, if that's desired.
Post by Horacio Villa
I can get around this by using the VALUE function inside the routine,
but
Post by Horacio Villa
I'd rather not. Is there another syntax that works better? Anyone
know?
I'm not sure what your objective is nor why you want to avoid value().
You might also conceal the stem with a "procedure", but then it wouldn't
be accessible in outer procedures.
-- gil
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-16 01:17:18 UTC
Permalink
Raw Message
Post by Horacio Villa
say value(stem||1)
I believe he said he wanted to avoid using "value()"
Post by Horacio Villa
From: Bob Bridges
Date: 03/15/2017 09:01 PM
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. But
so far I'm not doing very well. Maybe I'm just doing it wrong. Here's what
/* main routine */
call outtrap 'STEM.A.'
TSO command here<
call outtrap 'OFF'
say 'Outside' stem.A.1
call sub 'A'
...
/* sub routine */
arg Q
say 'Inside' stem.Q.1
return
But you can't DROP part of a compound, if that's desired.
Post by Horacio Villa
I can get around this by using the VALUE function inside the routine, but
I'd rather not. Is there another syntax that works better? Anyone know?
I'm not sure what your objective is nor why you want to avoid value().
You might also conceal the stem with a "procedure", but then it wouldn't
be accessible in outer procedures.

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Ward Able, Grant
2017-03-16 11:44:56 UTC
Permalink
Raw Message
Not sure if I am barking up the wrong tree here......
I notice that you call your sub using

call sub tss. (note the .)

but in the routine you use

arg stem (without a dot)

Have you tried this:

sub:
say 'Inside' tss.
say 'Inside' tss.1
say 'Inside' tss .1
return


or even

sub: PROCEDURE EXPOSE tss.



Regards - Grant.
Telephone Internal: 201496 (London)
Telephone External: +44 (0)207 650 1496

EAM - Enterprise Application Middleware

In theory, there's no difference between theory and practice. In practice, there is.

If you don't have time to do it right, when will you have the time to do it over? - John Wooden


-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Bob Bridges
Sent: 16 March 2017 00:01
To: TSO-***@VM.MARIST.EDU
Subject: [TSO-REXX] Can I pass a stem to an internal subroutine?

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. But so far I'm not doing very well. Maybe I'm just doing it wrong. Here's what I'm attempting:

/* main routine */
call outtrap 'TSS.'
TSO command here<
call outtrap 'OFF'
say 'Outside' tss.1
call sub tss.
...
/* sub routine */
sub:
arg stem
say 'Inside' stem.
say 'Inside' stem.1
say 'Inside' stem.1
return

I get back something like this:

Outside <contents of tss.1>
Inside TSS.
Inside TSS.
Inside TSS.

I can get around this by using the VALUE function inside the routine, but I'd rather not. Is there another syntax that works better? Anyone know?

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from "Military Pilots' Words of Wisdom" */

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions, send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
DTCC DISCLAIMER: This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error, please notify us immediately and delete the email and any attachments from your system. The recipient should check this email and any attachments for the presence of viruses. The company accepts no liability for any damage caused by any virus transmitted by this email.

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Dyck, Lionel B. , TRA
2017-03-16 12:02:32 UTC
Permalink
Raw Message
Check out CBTTape File 411 from Rob Scott:

Name : STEMPULL


Function : This program provides an external REXX function
to retrive REXX stem variables from the stack
created by the STEMPUSH function.

The 'stack' is in fact a dataspace whose STOKEN
is passed (in EBCDIC) from the STEMPUSH function.
This 'token' is used by this program to access
the dataspace and set up the REXX variables.

After the stack has been processed it is deleted
unless the user specifies the 'NODELETE' keyword.

Syntax : rcode = STEMPULL(token,delflag)

Name : STEMPUSH

Function : This program provides an external REXX function
to place REXX stem variables onto a stack that
can be passed to another REXX exec running within
the same address space.

The 'stack' is in fact a dataspace whose STOKEN
is passed back in EBCDIC form to the REXX result
value. This 'token' can then be used in any
other REXX as an argument to the STEMPULL
function to retrieve the contents of the
dataspace.

Syntax : token = STEMPUSH(maxblk,'stem1.',,'stemn.')

--------------------------------------------------------------------------
Lionel B. Dyck
Mainframe Systems Programmer - TRA
Enterprise Operations (Station 200) (005OP6.3.10)
Information and Technology, IT Operations and Services

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Ward Able, Grant
Sent: Thursday, March 16, 2017 6:45 AM
To: TSO-***@VM.MARIST.EDU
Subject: [EXTERNAL] Re: [TSO-REXX] Can I pass a stem to an internal subroutine?

Not sure if I am barking up the wrong tree here......
I notice that you call your sub using

call sub tss. (note the .)

but in the routine you use

arg stem (without a dot)

Have you tried this:

sub:
say 'Inside' tss.
say 'Inside' tss.1
say 'Inside' tss .1
return


or even

sub: PROCEDURE EXPOSE tss.



Regards - Grant.
Telephone Internal: 201496 (London)
Telephone External: +44 (0)207 650 1496

EAM - Enterprise Application Middleware

In theory, there's no difference between theory and practice. In practice, there is.

If you don't have time to do it right, when will you have the time to do it over? - John Wooden


-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Bob Bridges
Sent: 16 March 2017 00:01
To: TSO-***@VM.MARIST.EDU
Subject: [TSO-REXX] Can I pass a stem to an internal subroutine?

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. But so far I'm not doing very well. Maybe I'm just doing it wrong. Here's what I'm attempting:

/* main routine */
call outtrap 'TSS.'
TSO command here<
call outtrap 'OFF'
say 'Outside' tss.1
call sub tss.
...
/* sub routine */
sub:
arg stem
say 'Inside' stem.
say 'Inside' stem.1
say 'Inside' stem.1
return

I get back something like this:

Outside <contents of tss.1>
Inside TSS.
Inside TSS.
Inside TSS.

I can get around this by using the VALUE function inside the routine, but I'd rather not. Is there another syntax that works better? Anyone know?

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from "Military Pilots' Words of Wisdom" */

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions, send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX DTCC DISCLAIMER: This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error, please notify us immediately and delete the email and any attachments from your system. The recipient should check this email and any attachments for the presence of viruses. The company accepts no liability for any damage caused by any virus transmitted by this email.

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions, send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Hardee, Chuck
2017-03-16 12:20:07 UTC
Permalink
Raw Message
Bob,

I have a routine that has the following interface:

/*====================================================================*/
QuickSort: /* stemtosort,
start entry #,
end entry #
(, word # in entry) */

if arg(1,"O") then return -4
if arg(2,"O") then return -8
if arg(3,"O") then return -12

stemvarstate = symbol(arg(1))
select
when stemvarstate = "BAD" then return -16
when stemvarstate = "LIT" then return -20
when stemvarstate = "VAR" then NOP
otherwise return -24
end

if notvalidnumeric(arg(2)) then return -28

if notvalidnumeric(arg(3)) then return -32

if arg(4,"E") then
if notvalidnumeric(arg(4)) then return -36

QuickSortStem = arg(1)
StartEntry# = arg(2)
EndEntry# = arg(3)
WordToSortOn# = 1
if arg(4,"E") then WordToSortOn# = arg(4)

return QuickSortI(QuickSortStem, StartEntry#, EndEntry#, WordToSortOn#)

QuickSortI: procedure expose (QuickSortStem)
/*====================================================================*/

It's called like this:

/*====================================================================*/
mytable. = ""
ucstr = upperchrs
donestr = copies("_",length(ucstr))
i = random(1,length(ucstr))
k = 0
do forever
j = random(1,length(ucstr))
jc = substr(ucstr,j,1)
if jc \= "_" then do
k = k + 1
mytable.k = jc
ucstr = translate(ucstr,"_",jc)
end
if ucstr = donestr then leave
end
mytable.0 = length(ucstr)
showstr = ""
do i = 1 to length(ucstr)
showstr = showstr||mytable.i
end
say " Pre sort: '"showstr"'"
say QuickSort("mytable.",1,mytable.0)
showstr = ""
do i = 1 to length(ucstr)
showstr = showstr||mytable.i
end
say "Post sort: '"showstr"'"
if showstr = upperchrs then say "Success!"
else day "Failure!!!"
/*====================================================================*/

Basically, I can load any stem with a set of values and then call my quicksort routine to sort the stem and then return.
There is no pre-agreed upon name of the stem. It is dynamically passed via the interface stub (QuickSort) to the internal routine (QuickSortI).

Is this something like what you want to do?

Chuck

Charles (Chuck) Hardee
Senior Systems Engineer/Database Administration
EAS Information Technology

Thermo Fisher Scientific
300 Industry Drive | Pittsburgh, PA 15275
Phone +1 (724) 517-2633 | Mobile +1 (412) 877-2809 | FAX: +1 (412) 490-9230
***@ThermoFisher.com | www.thermofisher.com

WORLDWIDE CONFIDENTIALITY NOTE: Dissemination, distribution or copying of this e-mail or the information herein by anyone other than the intended recipient, or an employee or agent of a system responsible for delivering the message to the intended recipient, is prohibited. If you are not the intended recipient, please inform the sender and delete all copies.


-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Bob Bridges
Sent: Wednesday, March 15, 2017 8:01 PM
To: TSO-***@VM.MARIST.EDU
Subject: [TSO-REXX] Can I pass a stem to an internal subroutine?

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. But
so far I'm not doing very well. Maybe I'm just doing it wrong. Here's what
I'm attempting:

/* main routine */
call outtrap 'TSS.'
TSO command here<
call outtrap 'OFF'
say 'Outside' tss.1
call sub tss.
...
/* sub routine */
sub:
arg stem
say 'Inside' stem.
say 'Inside' stem.1
say 'Inside' stem.1
return

I get back something like this:

Outside <contents of tss.1>
Inside TSS.
Inside TSS.
Inside TSS.

I can get around this by using the VALUE function inside the routine, but
I'd rather not. Is there another syntax that works better? Anyone know?

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Robert Garrett
2017-03-16 14:02:55 UTC
Permalink
Raw Message
Hey Bob,

What's biting you is this: REXX will not substitute for the first level /
top level of a compound variable.
For instance:
TOP = 'MYSTEM';
SAY TOP.ELEMENT;
REXX will ignore the fact that variable TOP has been set to 'MYSTEM',
causing the second statement to continue to be a reference to a variable
named TOP.ELEMENT. Note this behavior only holds true for the first level.
It can and will substitute at any level other than the first.
For instance:
QUALIFIER = 'MINE';
SAY TOP. QUALIFIER.ELEMENT;
Will cause the SAY statement to reference TOP.MINE.ELEMENT (assuming that
ELEMENT has not also been set as a variable.

Hope this helps.
Rob

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of
Bob Bridges
Sent: Wednesday, March 15, 2017 7:01 PM
To: TSO-***@VM.MARIST.EDU
Subject: [TSO-REXX] Can I pass a stem to an internal subroutine?

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. But
so far I'm not doing very well. Maybe I'm just doing it wrong. Here's what
I'm attempting:

/* main routine */
call outtrap 'TSS.'
TSO command here<
call outtrap 'OFF'
say 'Outside' tss.1
call sub tss.
...
/* sub routine */
sub:
arg stem
say 'Inside' stem.
say 'Inside' stem.1
say 'Inside' stem.1
return

I get back something like this:

Outside <contents of tss.1>
Inside TSS.
Inside TSS.
Inside TSS.

I can get around this by using the VALUE function inside the routine, but
I'd rather not. Is there another syntax that works better? Anyone know?

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions, send email
to ***@VM.MARIST.EDU with the message: INFO TSO-REXX

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Bob Bridges
2017-03-16 14:52:22 UTC
Permalink
Raw Message
Thanks for all the replies.

1) The reason this came up is that I foresee having several different stems
in the main routine that will require similar processing; I wanted to be
able to call the subroutine using for exmaple aids. one time, and pfls.
later on in the program, and probably more.

2) I could pass the ~name~ of the stem and then in the subroutine manipulate
the stem using the VALUE function. The reason I didn't want to do that is
an intuitive supposition that it takes longer to process via VALUE, perhaps
much longer. I've never tested this and I suppose I should before
committing much effort to circumventing it, for VALUE of course would solve
the problem handily.

3) Several people mentioned using PROCEDURE and EXPOSE. I didn't bother
mentioning it but I did experiment with that before posting here, and got
the expected results: Without EXPOSE of course the subroutine couldn't see
the stem at all (ie it was uninitialized), and with EXPOSE it behaved the
same as without PROCEDURE. No help there that I can see.

4) Grant Able, I see the extra test you proposed ("say 'Inside' tss .1"). I
don't suppose it would solve the problem but off-hand it isn't clear to me
what it would produce; I may try it just out of curiosity :).

5) Lionel, I've heard of that STEMPUSH/STEMPULL thingy, but I'm not looking
for anything that fancy. (If I look deep within myself I think this is code
for "I've never pulled anything from CBTTape and it sounds new and difficult
and scary".)

6) Itschak pointed out that I can put the contents of the stem on the stack
before calling the routine, and since in this case all the entries are
numeric (the results of OUTTRAP) that would work fine. Maybe I will, in the
end. But since my first thought was to pass the stem itself, I posted here
at least as much out of intellectual curiosity; even if I end up doing it
another way, my question is ~can~ I pass a stem?

7) Both Chuck Hardee and Robert Garrett hint at the answer to that question.
Chuck's routine passes the ~name~ of the stem, and between his reply and
Robert's I come to understand: REXX doesn't pass variables at all, only
their values, a single character string for each argument. I guess I was
thinking in other languages, eg PL/1 and VBA, where it's possible to pass
the actual variable.

Even before I arrived at #7, I saw Gil's reply and did the dope slap: Of
course, all I need is one stem with an extra index! That's probably the way
I'll go in this case. Right, I can't do DROPs, but for this purpose I don't
think I want to anyway.

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */


-----Original Message-----
From: Paul Gilmartin [mailto:***@aim.com]
Sent: Wednesday, March 15, 2017 21:30
Post by Horacio Villa
---
From: Bob Bridges
Date: 03/15/2017 09:01 PM
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. But so far I'm not doing very well. Maybe I'm just
doing it wrong. Here's what
Could you add another index to the stem?

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Mike Holder
2017-03-16 15:02:01 UTC
Permalink
Raw Message
You could use INTERPRET but I doubt it would be any faster than VALUE.

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Bob Bridges
Sent: Thursday, March 16, 2017 10:53 AM
To: TSO-***@VM.MARIST.EDU
Subject: Re: Can I pass a stem to an internal subroutine?

Thanks for all the replies.

1) The reason this came up is that I foresee having several different stems
in the main routine that will require similar processing; I wanted to be
able to call the subroutine using for exmaple aids. one time, and pfls.
later on in the program, and probably more.

2) I could pass the ~name~ of the stem and then in the subroutine manipulate
the stem using the VALUE function. The reason I didn't want to do that is
an intuitive supposition that it takes longer to process via VALUE, perhaps
much longer. I've never tested this and I suppose I should before
committing much effort to circumventing it, for VALUE of course would solve
the problem handily.

3) Several people mentioned using PROCEDURE and EXPOSE. I didn't bother
mentioning it but I did experiment with that before posting here, and got
the expected results: Without EXPOSE of course the subroutine couldn't see
the stem at all (ie it was uninitialized), and with EXPOSE it behaved the
same as without PROCEDURE. No help there that I can see.

4) Grant Able, I see the extra test you proposed ("say 'Inside' tss .1"). I
don't suppose it would solve the problem but off-hand it isn't clear to me
what it would produce; I may try it just out of curiosity :).

5) Lionel, I've heard of that STEMPUSH/STEMPULL thingy, but I'm not looking
for anything that fancy. (If I look deep within myself I think this is code
for "I've never pulled anything from CBTTape and it sounds new and difficult
and scary".)

6) Itschak pointed out that I can put the contents of the stem on the stack
before calling the routine, and since in this case all the entries are
numeric (the results of OUTTRAP) that would work fine. Maybe I will, in the
end. But since my first thought was to pass the stem itself, I posted here
at least as much out of intellectual curiosity; even if I end up doing it
another way, my question is ~can~ I pass a stem?

7) Both Chuck Hardee and Robert Garrett hint at the answer to that question.
Chuck's routine passes the ~name~ of the stem, and between his reply and
Robert's I come to understand: REXX doesn't pass variables at all, only
their values, a single character string for each argument. I guess I was
thinking in other languages, eg PL/1 and VBA, where it's possible to pass
the actual variable.

Even before I arrived at #7, I saw Gil's reply and did the dope slap: Of
course, all I need is one stem with an extra index! That's probably the way
I'll go in this case. Right, I can't do DROPs, but for this purpose I don't
think I want to anyway.

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */


-----Original Message-----
From: Paul Gilmartin [mailto:***@aim.com]
Sent: Wednesday, March 15, 2017 21:30
Post by Horacio Villa
---
From: Bob Bridges
Date: 03/15/2017 09:01 PM
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. But so far I'm not doing very well. Maybe I'm just
doing it wrong. Here's what
Could you add another index to the stem?

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Mickey Bee
2017-03-16 15:17:17 UTC
Permalink
Raw Message
I have faced this problem before, and the solution was to pass just the name
of the stem, and use the Interpret command for there on.

Mickey

-----Original Message-----
From: Bob Bridges
Sent: Thursday, March 16, 2017 10:52 AM
To: TSO-***@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Can I pass a stem to an internal subroutine?

Thanks for all the replies.

1) The reason this came up is that I foresee having several different stems
in the main routine that will require similar processing; I wanted to be
able to call the subroutine using for exmaple aids. one time, and pfls.
later on in the program, and probably more.

2) I could pass the ~name~ of the stem and then in the subroutine manipulate
the stem using the VALUE function. The reason I didn't want to do that is
an intuitive supposition that it takes longer to process via VALUE, perhaps
much longer. I've never tested this and I suppose I should before
committing much effort to circumventing it, for VALUE of course would solve
the problem handily.

3) Several people mentioned using PROCEDURE and EXPOSE. I didn't bother
mentioning it but I did experiment with that before posting here, and got
the expected results: Without EXPOSE of course the subroutine couldn't see
the stem at all (ie it was uninitialized), and with EXPOSE it behaved the
same as without PROCEDURE. No help there that I can see.

4) Grant Able, I see the extra test you proposed ("say 'Inside' tss .1"). I
don't suppose it would solve the problem but off-hand it isn't clear to me
what it would produce; I may try it just out of curiosity :).

5) Lionel, I've heard of that STEMPUSH/STEMPULL thingy, but I'm not looking
for anything that fancy. (If I look deep within myself I think this is code
for "I've never pulled anything from CBTTape and it sounds new and difficult
and scary".)

6) Itschak pointed out that I can put the contents of the stem on the stack
before calling the routine, and since in this case all the entries are
numeric (the results of OUTTRAP) that would work fine. Maybe I will, in the
end. But since my first thought was to pass the stem itself, I posted here
at least as much out of intellectual curiosity; even if I end up doing it
another way, my question is ~can~ I pass a stem?

7) Both Chuck Hardee and Robert Garrett hint at the answer to that question.
Chuck's routine passes the ~name~ of the stem, and between his reply and
Robert's I come to understand: REXX doesn't pass variables at all, only
their values, a single character string for each argument. I guess I was
thinking in other languages, eg PL/1 and VBA, where it's possible to pass
the actual variable.

Even before I arrived at #7, I saw Gil's reply and did the dope slap: Of
course, all I need is one stem with an extra index! That's probably the way
I'll go in this case. Right, I can't do DROPs, but for this purpose I don't
think I want to anyway.

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */


-----Original Message-----
From: Paul Gilmartin [mailto:***@aim.com]
Sent: Wednesday, March 15, 2017 21:30
Post by Horacio Villa
---
From: Bob Bridges
Date: 03/15/2017 09:01 PM
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. But so far I'm not doing very well. Maybe I'm just
doing it wrong. Here's what
Could you add another index to the stem?

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-16 16:35:35 UTC
Permalink
Raw Message
Post by Bob Bridges
5) Lionel, I've heard of that STEMPUSH/STEMPULL thingy, but I'm not looking
for anything that fancy. (If I look deep within myself I think this is code
for "I've never pulled anything from CBTTape and it sounds new and difficult
and scary".)
A test I propose for any tool such as STEMPUSH/STEMPULL is:

/* Rexx */ signal on novalue

Stem. = 'Initial'
drop Stem.Moe
Stem.Curly = 'Assigned'

say 'Larry' symbol( 'Stem.Larry') value( 'Stem.Larry' )
say 'Moe ' symbol( 'Stem.Moe' ) value( 'Stem.Moe' )
say 'Curly' symbol( 'Stem.Curly') value( 'Stem.Curly' )

Which after STEMPUSH/STEMPULL should print:

513 $ rexx pass
Larry VAR Initial
Moe LIT STEM.MOE
Curly VAR Assigned

... the hard part is getting the "Moe" line to work correctly.
Rexx doesn't provide the needed API for this.
Post by Bob Bridges
Even before I arrived at #7, I saw Gil's reply and did the dope slap: Of
course, all I need is one stem with an extra index! That's probably the way
I'll go in this case. Right, I can't do DROPs, but for this purpose I don't
think I want to anyway.
Thanks. Also, as with DROP, you can't initialize only a single value of
the "extra index".
Stem. = 'everytning' /* works. */
Stem.A. = 'alfa' /* doesn't do what you might want. */

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Robert Garrett
2017-03-16 19:14:02 UTC
Permalink
Raw Message
If it helps any, I/we use STEMPUSH/STEMPULL at work in a "very large
financial institution environment" for various tooling that we would have a
very difficult time operating without.

A nice benefit of it, is that these routines enable passing compound
variable stems between *EXTERNAL* REXX routines, which I do extensively.
i.e. I have "various routines" that I use to gather configuration
information about various aspects of our operating landscape. These
routines organize the information they gather onto a stem structure which
they store with STEMPUSH, then they RETURN the resultant token back to the
external routine that called them, whereupon that calling routine uses that
token to retrieve the structure via STEMPULL. Works like a charm. REXX
doesn't directly support passing stems between externally called routines,
as you know.

Rob

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of
Paul Gilmartin
Sent: Thursday, March 16, 2017 11:36 AM
To: TSO-***@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Can I pass a stem to an internal subroutine?
Post by Bob Bridges
5) Lionel, I've heard of that STEMPUSH/STEMPULL thingy, but I'm not
looking for anything that fancy. (If I look deep within myself I
think this is code for "I've never pulled anything from CBTTape and it
sounds new and difficult and scary".)
A test I propose for any tool such as STEMPUSH/STEMPULL is:

/* Rexx */ signal on novalue

Stem. = 'Initial'
drop Stem.Moe
Stem.Curly = 'Assigned'

say 'Larry' symbol( 'Stem.Larry') value( 'Stem.Larry' )
say 'Moe ' symbol( 'Stem.Moe' ) value( 'Stem.Moe' )
say 'Curly' symbol( 'Stem.Curly') value( 'Stem.Curly' )

Which after STEMPUSH/STEMPULL should print:

513 $ rexx pass
Larry VAR Initial
Moe LIT STEM.MOE
Curly VAR Assigned

... the hard part is getting the "Moe" line to work correctly.
Rexx doesn't provide the needed API for this.
Post by Bob Bridges
Of course, all I need is one stem with an extra index! That's
probably the way I'll go in this case. Right, I can't do DROPs, but
for this purpose I don't think I want to anyway.
Thanks. Also, as with DROP, you can't initialize only a single value of the
"extra index".
Stem. = 'everytning' /* works. */
Stem.A. = 'alfa' /* doesn't do what you might want. */

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions, send email
to ***@VM.MARIST.EDU with the message: INFO TSO-REXX

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-16 19:30:27 UTC
Permalink
Raw Message
Post by Robert Garrett
If it helps any, I/we use STEMPUSH/STEMPULL at work in a "very large
financial institution environment" for various tooling that we would have a
very difficult time operating without.
And my test case? ...
Post by Robert Garrett
-----Original Message-----
From: Paul Gilmartin
Sent: Thursday, March 16, 2017 11:36 AM
/* Rexx */ signal on novalue
Stem. = 'Initial'
drop Stem.Moe
Stem.Curly = 'Assigned'
say 'Larry' symbol( 'Stem.Larry') value( 'Stem.Larry' )
say 'Moe ' symbol( 'Stem.Moe' ) value( 'Stem.Moe' )
say 'Curly' symbol( 'Stem.Curly') value( 'Stem.Curly' )
513 $ rexx pass
Larry VAR Initial
Moe LIT STEM.MOE
Curly VAR Assigned
... the hard part is getting the "Moe" line to work correctly.
Rexx doesn't provide the needed API for this.
-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Robert Garrett
2017-03-17 14:57:48 UTC
Permalink
Raw Message
I'm not sure you're understanding, so I put together a little demo:

Two separate EXEC's, stored as discreet members of a PDS:
First exec, stored as PDS member JRGTEST4:
/* REXX */
/*
Experimentation
Demonstrate the use of STEMPUSH/STEMPULL
*/

parse SOURCE . . THIS_ .;
THIS_ = STRIP(THIS_,'Both');
Say 'Running 'THIS_;

say THIS_,
'BEFORE',
'THESTEM.',
SYMBOL('THESTEM.0'),
THESTEM.0;
if SYMBOL('THESTEM.0') = 'VAR' then,
if DATATYPE(THESTEM.0) = 'NUM' then,
do ZINDEX = 1 to THESTEM.0;
say 'THESTEM.'ZINDEX': 'THESTEM.ZINDEX;
end ZINDEX;

/* Call external routine - retrieve token for STEMPULL */
parse value JRGTEST5() with _TOKEN;
call STEMPULL _TOKEN;

/* And now... */
say THIS_,
'AFTER',
'THESTEM.0',
SYMBOL('THESTEM.0'),
THESTEM.0;
if SYMBOL('THESTEM.0') = 'VAR' then,
if DATATYPE(THESTEM.0) = 'NUM' then,
do ZINDEX = 1 to THESTEM.0;
say THIS_,
'THESTEM.'ZINDEX':',
THESTEM.ZINDEX;
end ZINDEX;

say 'Exiting 'THIS_;
return 0;

Second EXEC, stored as PDS member JRGTEST5:
/* REXX */
/*
Experimentation
Demonstrate the use of STEMPUSH/STEMPULL
*/

parse SOURCE . . THIS_ .;
THIS_ = STRIP(THIS_,'Both');
Say 'Running 'THIS_;

THESTEM.1 = 'This';
THESTEM.2 = 'is';
THESTEM.3 = 'a';
THESTEM.4 = 'simple';
THESTEM.5 = 'demo';
THESTEM.6 = 'of STEMPUSH/STEMPULL';
THESTEM.0 = 6;

Say 'Exiting 'THIS_;
return STEMPUSH('THESTEM.');

When the first exec, JRGTEST4, is run it produces this output:
Running JRGTEST4
JRGTEST4 BEFORE THESTEM. LIT THESTEM.0
Running JRGTEST5
Exiting JRGTEST5
JRGTEST4 AFTER THESTEM.0 VAR 6
JRGTEST4 THESTEM.1: This
JRGTEST4 THESTEM.2: is
JRGTEST4 THESTEM.3: a
JRGTEST4 THESTEM.4: simple
JRGTEST4 THESTEM.5: demo
JRGTEST4 THESTEM.6: of STEMPUSH/STEMPULL
Exiting JRGTEST4

STEMPUSH and STEMPULL, from the CBT 'tape', are both assembler generated
load modules - not REXX code. STEMPUSH creates a dataspace associated with
the jobstep TCB and uses it to store the data. The token it passes back is
in fact an EBCDIC-ized STOKEN value that STEMPULL uses to connect to the
dataspace, fetch the data from it, and use REXX services to re-create all
the variables in the local REXX environment. There are parameters on the
STEMPULL call that can be used to control the disposition of the dataspace
after its contents have been fetched. It can be destroyed (the default
action), or kept around (possibly for use by other callers).

Robert

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of
Paul Gilmartin
Sent: Thursday, March 16, 2017 2:31 PM
To: TSO-***@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Can I pass a stem to an internal subroutine?
Post by Robert Garrett
If it helps any, I/we use STEMPUSH/STEMPULL at work in a "very large
financial institution environment" for various tooling that we would
have a very difficult time operating without.
And my test case? ...
Post by Robert Garrett
-----Original Message-----
From: Paul Gilmartin
Sent: Thursday, March 16, 2017 11:36 AM
/* Rexx */ signal on novalue
Stem. = 'Initial'
drop Stem.Moe
Stem.Curly = 'Assigned'
say 'Larry' symbol( 'Stem.Larry') value( 'Stem.Larry' )
say 'Moe ' symbol( 'Stem.Moe' ) value( 'Stem.Moe' )
say 'Curly' symbol( 'Stem.Curly') value( 'Stem.Curly' )
513 $ rexx pass
Larry VAR Initial
Moe LIT STEM.MOE
Curly VAR Assigned
... the hard part is getting the "Moe" line to work correctly.
Rexx doesn't provide the needed API for this.
-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions, send email
to ***@VM.MARIST.EDU with the message: INFO TSO-REXX

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Phil Smith III
2017-03-17 14:31:29 UTC
Permalink
Raw Message
I've written products in Rexx, including servers, and long ago adopted a few
conventions:

1) Subroutines/functions are always PROCEDUREs (except in very rare cases,
heavily documented)

2) Global variables all start with specific stems, such as G., and are
EXPOSEd in the
subroutines/functions

3) Tails (the part after the first dot) always start with an underscore, and
I never assign any variables with names starting with an underscore (you
could also start tails with a number, since variable names can't start with
a number, but that's ugly IMHO)

So a function might look like:

SomeFunction: Procedure expose g. c. u.

Where stems G. C. and U. are (perhaps) global data, configuration data, and
user data. And the actual variables include (perhaps) G._USERID,
C._URLSETTING, and U._OPTION.1

This allows me to manage the variables pretty simply: the underscore
convention means I never get into trouble with a stem getting interpreted
when I don't want it to be, and local variables in subroutines/functions are
just that.

In servers, one of those G. variables is G._DEBUG, which can be set
externally via command; each function/subroutine then includes:

SomeFunction: Procedure expose g. c. u.
if wordpos('SOMEFUNCTION', g._debug) > 0 then trace ?r

(or other appropriate TRACE setting). This lets me set "breakpoints" when
needed.

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-17 19:56:34 UTC
Permalink
Raw Message
Post by Phil Smith III
2) Global variables all start with specific stems, such as G., and are
EXPOSEd in the subroutines/functions
The parenthesized EXPOSE list is precious.
Post by Phil Smith III
3) Tails (the part after the first dot) always start with an underscore, and
I never assign any variables with names starting with an underscore (you
could also start tails with a number, since variable names can't start with
a number, but that's ugly IMHO)
Ugly, but the safest way. I do it. Are there no other names
that can't be variable names?

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Jeremy Nicoll
2017-03-18 07:56:58 UTC
Permalink
Raw Message
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
functions)
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 body
of
any exec / external function that used them. My method is unlikely to
be
any use if you're just wanting to use code within a single exec.


From something I wrote ages ago:


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 but
value() replaced that. Usage would be something like:

fred.1 = "horse"
fred.2 = ""
fred.3 = "cow"
fred.4 = "in the field"
fred.0 = 4
fredlong = pak("fred.")
return fredlong

The returned result ends up with a string comprising the number of
fields
(in this case 4) and their lengths, then the actual text string, so it
would be something like:

"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,
say:

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)


If you have several arrays to pass back you can just do something like:

temp.1 = pak("fred.")
temp.2 = pak("john.")
temp.3 = pak("mark.")
temp.0 = 3
return pak("temp.")

and then of course you have two stages of haking to do.

The basic pak function looks like:



pak: /*--------------------------------------------------------*/
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
end
return num#vec txt#vec /* return value is packed string! */



and hak is:



hak: /*---------------------------------------------------------------*/
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' */
end
do token = 1 to numv
st = siz.token
assign = value(stem||token,substr(rest,1,st))
rest = substr(rest,st+1)
end
return numv /* return value is number of variables */



Some obvious points:

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 something
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 saves
time.

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. For example if the max
data length is 4, you could have a text part like:

"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 structure so
that the stem name is included, ie:

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
duplicated
stem element values are only stored once, and so on. I once wrote a
sort
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.

--
Jeremy Nicoll - my opinions are my own.

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Hobart Spitz
2017-03-19 14:41:05 UTC
Permalink
Raw Message
The short answer to the subject question is: Yes. Use VALUE(), period.

The long answer is:

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

Example 1:

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". */

...
exit
...
Fred.: /* Like value(), but for 1 stem. */

Item = "Fred."arg(1)

if arg(2, "e") then

return value(Item, arg(2))

return value(Item)


You could generalize it, but then it's exactly the same a VALUE().

Example 2:

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

...

exit

...

/* Add arg elements to stem implemented array. */


Stem.Append:


arg StemName


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


drop (StemName)

end




do iStemArg = 2 to arg()


LastItem = LastItem + 1


call value StemName || LastItem, arg(iStemArg)


end iStemArg



call value Tail, LastItem




return


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
functions)
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 body
of
any exec / external function that used them. My method is unlikely to
be
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 but
fred.1 = "horse"
fred.2 = ""
fred.3 = "cow"
fred.4 = "in the field"
fred.0 = 4
fredlong = pak("fred.")
return fredlong
The returned result ends up with a string comprising the number of
fields
(in this case 4) and their lengths, then the actual text string, so it
"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
return pak("temp.")
and then of course you have two stages of haking to do.
pak: /*--------------------------------------------------------*/
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
end
return num#vec txt#vec /* return value is packed string! */
hak: /*---------------------------------------------------------------*/
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' */
end
do token = 1 to numv
st = siz.token
assign = value(stem||token,substr(rest,1,st))
rest = substr(rest,st+1)
end
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 something
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 saves
time.
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. For example if the max
"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 structure so
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
duplicated
stem element values are only stored once, and so on. I once wrote a
sort
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.
--
Jeremy Nicoll - my opinions are my own.
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
--
OREXXMan

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-19 15:06:43 UTC
Permalink
Raw Message
Post by Hobart Spitz
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.
And such numbers are not canonicalized. Manipulating Stem.0123E4 does
not affect Stem.00123E4 or Stem.01230E3, but does affect Stem.0123e4.

What risk do you see in using 0123E4?

Use double equal sign when comparing.

I suppose there's some hazard in using a variable as a tail which
has a numeric value with length exceeding NUMERIC DIGITS.

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Bob Bridges
2017-03-22 22:14:37 UTC
Permalink
Raw Message
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 try parens; I'd always done it this way:

x=stem.ja+1

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.

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from "Military Pilots' Words of Wisdom" */


-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Hobart Spitz
Sent: Sunday, March 19, 2017 10:42

The short answer to the subject question is: Yes. Use VALUE(), period.

The long answer is:

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

Example 1:

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". */

...
exit
...
Fred.: /* Like value(), but for 1 stem. */

Item = "Fred."arg(1)

if arg(2, "e") then

return value(Item, arg(2))

return value(Item)


You could generalize it, but then it's exactly the same a VALUE().

Example 2:

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

...

exit

...

/* Add arg elements to stem implemented array. */


Stem.Append:


arg StemName


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


drop (StemName)

end




do iStemArg = 2 to arg()


LastItem = LastItem + 1


call value StemName || LastItem, arg(iStemArg)


end iStemArg



call value Tail, LastItem




return


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.
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
functions)
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
body of
any exec / external function that used them. My method is unlikely to
be
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
but
fred.1 = "horse"
fred.2 = ""
fred.3 = "cow"
fred.4 = "in the field"
fred.0 = 4
fredlong = pak("fred.")
return fredlong
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
return pak("temp.")
and then of course you have two stages of haking to do.
pak: /*--------------------------------------------------------*/
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
end
return num#vec txt#vec /* return value is packed string! */
hak: /*---------------------------------------------------------------*/
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' */
end
do token = 1 to numv
st = siz.token
assign = value(stem||token,substr(rest,1,st))
rest = substr(rest,st+1)
end
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 something
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 saves
time.
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. For example if the max
"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 structure so
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
duplicated
stem element values are only stored once, and so on. I once wrote a
sort
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 email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Steve Beaver
2017-03-22 22:18:50 UTC
Permalink
Raw Message
One rule -- Try it -- it might actually work

Steve

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Bob Bridges
Sent: Wednesday, March 22, 2017 5:14 PM
To: TSO-***@VM.MARIST.EDU
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 try parens; I'd always done it this way:

x=stem.ja+1

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.

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* The only time you have too much fuel is when you're on fire. -from "Military Pilots' Words of Wisdom" */


-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Hobart Spitz
Sent: Sunday, March 19, 2017 10:42

The short answer to the subject question is: Yes. Use VALUE(), period.

The long answer is:

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

Example 1:

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". */

...
exit
...
Fred.: /* Like value(), but for 1 stem. */

Item = "Fred."arg(1)

if arg(2, "e") then

return value(Item, arg(2))

return value(Item)


You could generalize it, but then it's exactly the same a VALUE().

Example 2:

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

...

exit

...

/* Add arg elements to stem implemented array. */


Stem.Append:


arg StemName


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


drop (StemName)

end




do iStemArg = 2 to arg()


LastItem = LastItem + 1


call value StemName || LastItem, arg(iStemArg)


end iStemArg



call value Tail, LastItem




return


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.
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
functions)
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
body of
any exec / external function that used them. My method is unlikely to
be
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
but
fred.1 = "horse"
fred.2 = ""
fred.3 = "cow"
fred.4 = "in the field"
fred.0 = 4
fredlong = pak("fred.")
return fredlong
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
return pak("temp.")
and then of course you have two stages of haking to do.
pak: /*--------------------------------------------------------*/
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
end
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' */
end
do token = 1 to numv
st = siz.token
assign = value(stem||token,substr(rest,1,st))
rest = substr(rest,st+1)
end
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
something
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 saves
time.
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. For example if
"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 structure
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
duplicated
stem element values are only stored once, and so on. I once wrote a
sort
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 email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Hobart Spitz
2017-03-23 00:02:11 UTC
Permalink
Raw Message
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
Steve
-----Original Message-----
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 try
x=stem.ja+1
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.
---
Bob Bridges
/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */
-----Original Message-----
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". */
...
exit
...
Fred.: /* Like value(), but for 1 stem. */
Item = "Fred."arg(1)
if arg(2, "e") then
return value(Item, arg(2))
return value(Item)
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
...
exit
...
/* Add arg elements to stem implemented array. */
arg StemName
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
drop (StemName)
end
do iStemArg = 2 to arg()
LastItem = LastItem + 1
call value StemName || LastItem, arg(iStemArg)
end iStemArg
call value Tail, LastItem
return
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
functions)
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
body of
any exec / external function that used them. My method is unlikely to
be
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
but
fred.1 = "horse"
fred.2 = ""
fred.3 = "cow"
fred.4 = "in the field"
fred.0 = 4
fredlong = pak("fred.")
return fredlong
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
return pak("temp.")
and then of course you have two stages of haking to do.
pak: /*--------------------------------------------------------*/
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
end
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' */
end
do token = 1 to numv
st = siz.token
assign = value(stem||token,substr(rest,1,st))
rest = substr(rest,st+1)
end
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
something
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 saves
time.
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. For example if
"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 structure
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
duplicated
stem element values are only stored once, and so on. I once wrote a
sort
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 email
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
--
OREXXMan

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Nims,Alva John , Al
2017-03-23 13:42:30 UTC
Permalink
Raw Message
How does a function like OUTTRAP handle a STEM Variable name being passed to it as a string?

X = OUTTRAP("MyStem.")

Hmm, does the use of VALUE function make that work?

Al Nims
Systems Admin/Programmer 3
UFIT
University of Florida
(352) 273-1298

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Hobart Spitz
Sent: Wednesday, March 22, 2017 8:03 PM
To: TSO-***@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Can I pass a stem to an internal subroutine?

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
Steve
-----Original Message-----
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
x=stem.ja+1
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.
---
Bob Bridges
/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */
-----Original Message-----
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". */
...
exit
...
Fred.: /* Like value(), but for 1 stem. */
Item = "Fred."arg(1)
if arg(2, "e") then
return value(Item, arg(2))
return value(Item)
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
...
exit
...
/* Add arg elements to stem implemented array. */
arg StemName
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
drop (StemName)
end
do iStemArg = 2 to arg()
LastItem = LastItem + 1
call value StemName || LastItem, arg(iStemArg)
end iStemArg
call value Tail, LastItem
return
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
functions)
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
body of
any exec / external function that used them. My method is unlikely to
be
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
but
fred.1 = "horse"
fred.2 = ""
fred.3 = "cow"
fred.4 = "in the field"
fred.0 = 4
fredlong = pak("fred.")
return fredlong
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
return pak("temp.")
and then of course you have two stages of haking to do.
pak: /*--------------------------------------------------------*/
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
end
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' */
end
do token = 1 to numv
st = siz.token
assign = value(stem||token,substr(rest,1,st))
rest = substr(rest,st+1)
end
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
something
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
saves time.
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
duplicated
stem element values are only stored once, and so on. I once wrote a
sort
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
--
OREXXMan

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions, send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-23 14:19:20 UTC
Permalink
Raw Message
Post by Nims,Alva John , Al
How does a function like OUTTRAP handle a STEM Variable name being passed to it as a string?
X = OUTTRAP("MyStem.")
Hmm, does the use of VALUE function make that work?
In the Rexx Reference, see:
Chapter 12. TSO/E REXX programming services
Variable access routine - IRXEXCOM

... That's probably what makes the VALUE() function work.

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Hobart Spitz
2017-03-23 14:40:47 UTC
Permalink
Raw Message
My information may be out of date, but I think REXX provides a variable
interface API that in turn calls TSO's IKJCT441.

IKJCT441 similar to in fuction to VALUE() with at least one difference:
VALUE() can't tell you if a variable is uninitialized; you just get name
name in upper case and that is indistinguishable from a variable that is
initialized to it's own uppercased name.

I doubt that you can call IKJCT441 from REXX without a lot trouble
(ADDRESS LINKMVS
or LINKPGM maybe?).
Post by Nims,Alva John , Al
How does a function like OUTTRAP handle a STEM Variable name being passed
to it as a string?
X = OUTTRAP("MyStem.")
Hmm, does the use of VALUE function make that work?
Al Nims
Systems Admin/Programmer 3
UFIT
University of Florida
(352) 273-1298
-----Original Message-----
Sent: Wednesday, March 22, 2017 8:03 PM
Subject: Re: [TSO-REXX] Can I pass a stem to an internal subroutine?
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
Steve
-----Original Message-----
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
x=stem.ja+1
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.
Post by Steve Beaver
---
Bob Bridges
/* The only time you have too much fuel is when you're on fire. -from
"Military Pilots' Words of Wisdom" */
-----Original Message-----
Behalf Of Hobart Spitz
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().
Post by Steve Beaver
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,..
Post by Steve Beaver
*/
/* ..FRED.wkdy the rest of the week, perhaps, and sets the item to "newval". */
...
exit
...
Fred.: /* Like value(), but for 1 stem. */
Item = "Fred."arg(1)
if arg(2, "e") then
return value(Item, arg(2))
return value(Item)
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.
Post by Steve Beaver
...
call Stem.Append "Fred.", a, b, c
...
exit
...
/* Add arg elements to stem implemented array. */
arg StemName
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
drop (StemName)
end
do iStemArg = 2 to arg()
LastItem = LastItem + 1
call value StemName || LastItem, arg(iStemArg)
end iStemArg
call value Tail, LastItem
return
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.
Post by Steve Beaver
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
functions)
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
body of
any exec / external function that used them. My method is unlikely
to
Post by Steve Beaver
Post by Jeremy Nicoll
be
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
but
fred.1 = "horse"
fred.2 = ""
fred.3 = "cow"
fred.4 = "in the field"
fred.0 = 4
fredlong = pak("fred.")
return fredlong
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
return pak("temp.")
and then of course you have two stages of haking to do.
pak: /*--------------------------------------------------------*/
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
end
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'
*/
Post by Steve Beaver
Post by Jeremy Nicoll
siz.token = word(rest,1) /* eg: '5' or '5'
*/
Post by Steve Beaver
Post by Jeremy Nicoll
hak##chars = length(siz.token)
rest = substr(rest,hak##chars+2) /* eg: 'abbot' or ' bit'
*/
Post by Steve Beaver
Post by Jeremy Nicoll
end
do token = 1 to numv
st = siz.token
assign = value(stem||token,substr(rest,1,st))
rest = substr(rest,st+1)
end
return numv /* return value is number of variables
*/
Post by Steve Beaver
Post by Jeremy Nicoll
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
something
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
saves time.
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.
For example if the max data length is 4, you could have a text part
"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
duplicated
stem element values are only stored once, and so on. I once wrote a
sort
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.
Post by Steve Beaver
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions, send
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions, send
--
OREXXMan
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions, send email
--
OREXXMan

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-23 14:26:57 UTC
Permalink
Raw Message
Post by 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.
I've read that optimization of the parser was the motivation for
eschewing expressions as compound tails. Assignments can be recognized
and the code can bypass recursive descent parsing. I can't envision
much advantage there.

FORTRAN facilitated operator strength reduction by restricting
subscript syntax. I see no parallel in Rexx.

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-22 22:40:14 UTC
Permalink
Raw Message
Post by Bob Bridges
x=stem.ja+1
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.
That really shouldn't work. It's a function call, isn't it?

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Aviatrexx
2017-03-24 01:19:36 UTC
Permalink
Raw Message
Of course it won't, as Hobart and others have pointed out.

OTOH, the most frequent circumstance where I find myself in need of the ability to use an expression as a tail, is when adding a new element to a monotonic stem array:

Parse Value mystem.0+1 newvalue With nxt mystem.nxt =1 mystem.0 .

It beats the hex out of the equivalent five clause Do-End group.

-Chip-
Post by Bob Bridges
x=stem.ja+1
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.
Phil Smith III
2017-03-23 17:18:41 UTC
Permalink
Raw Message
Post by 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.
Phew. I thought I was losing it--I read the above posts and was sure this
wouldn't work, even went and tried it on z/VM!

And when I did try it:

a.xyz = banana
b = 1
say value('A.'b+1)
SYNTAX ERROR 15: Invalid hexadecimal or binary string

Oops, yeah:
say value('A.'1+b)
XYZ

Heh.

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-23 17:42:50 UTC
Permalink
Raw Message
Post by Phil Smith III
...
Phew. I thought I was losing it--I read the above posts and was sure this
wouldn't work, even went and tried it on z/VM!
a.xyz = banana
b = 1
say value('A.'b+1)
SYNTAX ERROR 15: Invalid hexadecimal or binary string
say value('A.'1+b)
XYZ
??? I'd certainly have expected:
say value('A.'1+b)
A.2

... ( absent a prior assignment: a. = 'XYZ' )

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Doug Behrends
2017-03-23 21:45:42 UTC
Permalink
Raw Message
That's why I NEVER use X or B as a variable. Too often I've had it
interpreted as HEXADECIMAL or BINARY indicator

Doug Behrends
Sr Professional Services Consultant

VANGUARD Integrity Professionals
Enterprise Security Software
6625 S. Eastern Avenue, Suite 100
Las Vegas, Nevada 89119
Post by Phil Smith III
Post by 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
Post by Hobart Spitz
function call, not a stem reference.
Phew. I thought I was losing it--I read the above posts and was sure this
wouldn't work, even went and tried it on z/VM!
a.xyz = banana
b = 1
say value('A.'b+1)
SYNTAX ERROR 15: Invalid hexadecimal or binary string
say value('A.'1+b)
XYZ
Heh.
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-23 22:13:35 UTC
Permalink
Raw Message
Post by Doug Behrends
That's why I NEVER use X or B as a variable. Too often I've had it
interpreted as HEXADECIMAL or BINARY indicator
Don't forget unintended floating point numbers. Use == rather
than = for comparison. (It's faster, too, for just the price
of one keystroke.)

ISPF is worse. The modifier can either precede or follow the
delimited string.
Post by Doug Behrends
Post by Phil Smith III
say value('A.'b+1)
SYNTAX ERROR 15: Invalid hexadecimal or binary string
say value('A.'1+b)
XYZ
-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Bob Bridges
2017-03-24 21:27:11 UTC
Permalink
Raw Message
Same here, but I took it a step further: I stopped using ~any~ one-character variable names. For all my temporary variables, the ones that I'm using too briefly to think much about their names, I call them v-something, like va for an address or vt for a timestamp, whatever takes my fancy at the time. Sometimes the prefix is 'l' if it's for length of a string, or p-something for the position in a string, and all my flags (ie Boolean values) are f-something, and all my loop indices are j-something. That last is after a brief fling with i-something; I encountered too many letters that don't mix well with 'i' either because they're reserved words (if, in, is) or are just confusing (id, ie, it). But never again one-character names, because I once tried to concatenate a temp variable 'x' to a character string and then spent 'way too much time trying to figure out what was wrong with 'command 'x.

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* If our religion is something objective, then we must never avert our eyes from those elements in it which seem puzzling or repellent; for it will be precisely the puzzling or the repellent which conceals what we do not yet know and need to know. -CS Lewis, "The Weight of Glory" */


-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Doug Behrends
Sent: Thursday, March 23, 2017 17:45
To: TSO-***@VM.MARIST.EDU

That's why I NEVER use X or B as a variable. Too often I've had it interpreted as HEXADECIMAL or BINARY indicator
Post by Phil Smith III
Phew. I thought I was losing it--I read the above posts and was sure
this wouldn't work, even went and tried it on z/VM!
a.xyz = banana
b = 1
say value('A.'b+1)
SYNTAX ERROR 15: Invalid hexadecimal or binary string
say value('A.'1+b)
XYZ
Heh.
Post by 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.
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Hobart Spitz
2017-03-24 21:38:19 UTC
Permalink
Raw Message
I assume that everybody realizes that even if you can't write; 'ijk'x to
concatenate, you still always write 'ijk' || x.
Post by Bob Bridges
Same here, but I took it a step further: I stopped using ~any~
one-character variable names. For all my temporary variables, the ones
that I'm using too briefly to think much about their names, I call them
v-something, like va for an address or vt for a timestamp, whatever takes
my fancy at the time. Sometimes the prefix is 'l' if it's for length of a
string, or p-something for the position in a string, and all my flags (ie
Boolean values) are f-something, and all my loop indices are j-something.
That last is after a brief fling with i-something; I encountered too many
letters that don't mix well with 'i' either because they're reserved words
(if, in, is) or are just confusing (id, ie, it). But never again
one-character names, because I once tried to concatenate a temp variable
'x' to a character string and then spent 'way too much time trying to
figure out what was wrong with 'command 'x.
---
Bob Bridges
/* If our religion is something objective, then we must never avert our
eyes from those elements in it which seem puzzling or repellent; for it
will be precisely the puzzling or the repellent which conceals what we do
not yet know and need to know. -CS Lewis, "The Weight of Glory" */
-----Original Message-----
Sent: Thursday, March 23, 2017 17:45
That's why I NEVER use X or B as a variable. Too often I've had it
interpreted as HEXADECIMAL or BINARY indicator
Post by Phil Smith III
Phew. I thought I was losing it--I read the above posts and was sure
this wouldn't work, even went and tried it on z/VM!
a.xyz = banana
b = 1
say value('A.'b+1)
SYNTAX ERROR 15: Invalid hexadecimal or binary string
say value('A.'1+b)
XYZ
Heh.
Post by 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.
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
--
OREXXMan

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Bob Bridges
2017-03-27 19:48:15 UTC
Permalink
Raw Message
LOL, good point. I don't remember whether I thought of that at the time, but now that I've been using two-letter variable names for a while I think it's probably better practice anyway; I'm happy I made the change.

---
Bob Bridges
***@gmail.com, cell 336 382-7313
***@InfoSecInc.com

/* Never miss a good chance to shut up. -from A Cowboy's Guide to Life */

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-***@VM.MARIST.EDU] On Behalf Of Hobart Spitz
Sent: Friday, March 24, 2017 17:39

I assume that everybody realizes that even if you can't write; 'ijk'x to concatenate, you still always write 'ijk' || x.
Post by Bob Bridges
Same here, but I took it a step further: I stopped using ~any~
one-character variable names. For all my temporary variables, the
ones that I'm using too briefly to think much about their names, I
call them v-something, like va for an address or vt for a timestamp,
whatever takes my fancy at the time. Sometimes the prefix is 'l' if
it's for length of a string, or p-something for the position in a
string, and all my flags (ie Boolean values) are f-something, and all my loop indices are j-something.
That last is after a brief fling with i-something; I encountered too
many letters that don't mix well with 'i' either because they're
reserved words (if, in, is) or are just confusing (id, ie, it). But
never again one-character names, because I once tried to concatenate a
temp variable 'x' to a character string and then spent 'way too much
time trying to figure out what was wrong with 'command 'x.
-----Original Message-----
Sent: Thursday, March 23, 2017 17:45
That's why I NEVER use X or B as a variable. Too often I've had it
interpreted as HEXADECIMAL or BINARY indicator
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-03-24 21:58:11 UTC
Permalink
Raw Message
Post by Bob Bridges
Same here, but I took it a step further: I stopped using ~any~ one-character variable names. For all my temporary variables, the ones that I'm using too briefly to think much about their names, I call them v-something, like va for an address or vt for a timestamp, whatever takes my fancy at the time. Sometimes the prefix is 'l' if it's for length of a string, or p-something for the position in a string, and all my flags (ie Boolean values) are f-something, and all my loop indices are j-something. That last is after a brief fling with i-something; I encountered too many letters that don't mix well with 'i' either because they're reserved words (if, in, is) or are just confusing (id, ie, it). But never again one-character names, because I once tried to concatenate a temp variable 'x' to a character string and then spent 'way too much time trying to figure out what was wrong with 'command 'x.
https://en.wikipedia.org/wiki/Hungarian_notation

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Glenn Knickerbocker
2017-04-04 22:10:03 UTC
Permalink
Raw Message
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.
The good workaround I've seen for this is to use substems: Put
everything in one main stem, and pass the first symbol of the tail as
the name of the substem.

Call OutTrap 'MAIN.TSS.'
TSOcommand
Call OutTrap 'OFF'
Call Sub 'TSS'
...

Sub: Procedure Expose main.
Arg sub
Say main.sub.1
...

¬R

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Paul Gilmartin
2017-04-04 22:50:21 UTC
Permalink
Raw Message
Post by Glenn Knickerbocker
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.
The good workaround I've seen for this is to use substems: Put
everything in one main stem, and pass the first symbol of the tail as
the name of the substem.
Call OutTrap 'MAIN.TSS.'
TSOcommand
Call OutTrap 'OFF'
Call Sub 'TSS'
...
Sub: Procedure Expose main.
Arg sub
Say main.sub.1
...
The shortcoming of this is that mass assignment, DROP, and EXPOSE
don't work for such substems. I.e.:
procedure expose main.sub.
main.sub. = "Initialized"
drop main.sub.

... don't operate on the entire substem as you might wish.

-- gil

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
Loading...