A Critique of Rexx [LONG]

16 views
Skip to first unread message

Phil Bewig

unread,
Aug 22, 1993, 11:15:09 PM8/22/93
to

Critique of Rexx, and a procedure library


I am an accountant and occasional programmer, and will soon
be moving to OS/2 from a Unix and DOS background. I have
decided to learn Rexx because of the universal macro
capability it provides to OS/2 applications. My vehicle for
learning Rexx has been a port of Jon Bentley's procedure
library, which is appended to this message. I am writing
this message to clarify in my own mind my experiences with
Rexx and help determine how Rexx will fit my accounting,
spreadsheet and database work on OS/2.

There are numerous rules of syntax and semantics in Rexx
which are a nuisance because they so frequently require
extra code to work around. The most obvious problem is the
prohibition of expressions in the tail of a compound
variable: "x.i+1" parses as "(x.i)+1" and "x.(i+1)" is
illegal, and must be written as "iplus1=i+1; x.iplus1"
instead. There are no records or structs, so a programmer
must resort to the old fortran trick of parallel arrays.
All elements in a conditional expression are evaluated,
preventing the "short-circuit" evaluation of conditions as
in C; the C condition "if i < maxi && x.i < x/i+1 ..." must
be rewritten as two separate if statements in Rexx:

if i < maxi then do
iplus1 = i + 1
if x.i < x.iplus1 then do
...
end
end

where the previous "i=iplus1" problem makes matters even
worse. And there are doubtless other examples of nuisance
syntax and semantics. These problems don't affect the final
capability of code, but they reduce programmer efficiency by
making code larger, harder to read, and harder to debug
("hmm -- did iplus1 get updated every time i was updated"?).

The lack of "pass by reference" for compound variables is a
serious bar to writing general-purpose procedures. In the
attached procedure library, in most other languages it
would be possible to make the name of the compound variable
to be sorted a parameter to the sort procedure. But because
Rexx passes all variables by value, there is no way to pass
or return a sorted compound variable. I solved the problem
in my procedure library by always operating on the global
variable x., but this is hardly a general solution.

In general, Rexx requires too many variables to be global.
There are no static variables, so any variable which is
local to a procedure but must retain its value between calls
of the procedure must be global. There is no fortran-like
common, so any variable which must be shared between
non-hierarchically-related procedures must be global. The
problem of "pass by reference" discussed previously may
result in variables being made global. Any variable which
is to be initialized must be global, because otherwise its
scope is only the procedure in which it is initialized. Of
course, the sins of global variables are well known to most
programmers, causing increased program complexity and
lengthier debugging.

One problem which sounds simple but has the capacity to do
great harm is the lack of any syntactic limits on a
procedure. Execution continues in a Rexx procedure until a
RETURN is seen; given SIGNALs, that can be anywhere in a
program. Although that's not normally a problem, since most
programs raise few SIGNALs, consider this scenario: during
program development or maintenance, a procedure which is a
large "if ... else if ... else" chain, with each alternative
in the chain processing its own return, is modified so that
none of the alternatives is selected, so that control flow
drops through to the next procedure, where it is unlikely to
do anything useful. In general, considering the problem
from the standpoint of program verification, the lack of
syntactic limits on procedures means that an entire program
must be inspected at once, instead of breaking it into
smaller pieces.

Although a program can create an arbitrary number of tails
for a single compound variable, Rexx makes no provision to
iterate over all of the tails, as in the "for (i in x)" loop
of awk. This problem is apparent in the checksubs procedure
of the attached library, which attempts to test that the
final tails of a compound variable are a permutation of the
original tails, as asserted by the problem definition. The
obvious solution is to keep a parallel array of tails
("xtails.1 to xtails.n, with xtails.count = n"), though this
may be hard to do generally. I ignored the problem in my
procedure library.

Some implementations of Rexx offer solutions to some of
these problems. The Rexx I have been using while waiting to
switch to OS/2 is IMC/rexx for unix (available via anonymous
ftp from rexx.uwaterloo.ca). IMC/rexx allows parenthesized
expressions in the tails of compound variables, and a
PROCEDURE HIDE declaration eases the problem of global
variables, without eliminating it. Of course, such
non-portable solutions leave a lot to be desired.

My overall conclusion is that Rexx is ill-suited for
"programming in the large." During the writing of my
procedure library, I stumbled over most of the problems
mentioned above. With practice, I will probably do better,
but some of the problems -- no "short-circuit" evaluation,
no "pass by reference" for compound variables, too many
globals, no syntactic limits on procedures -- are
fundamental to the language and have profound effects on
debugging and program verification.

Of course, Rexx was initially intended as a shell scripting
and general-purpose macro language, and for these purposes
it works well enough. I'll use Rexx with my OS/2
applications work to move data between applications, perhaps
laundering it along the way, or to write scripts that invoke
multiple applications. But I'll use other languages for
applications development, as they are suitable to the task
at hand.

I appreciate your thoughtful comments. In particular, I
solicit comments from programmers who have experience with
Rexx for writing large, complex programs.

Phil
pbe...@netcom.com

NOTE: My port of Jon Bentley's procedure library is shown
below:

/* bentley.rexx -- jon bentley's subroutine library, ported from awk
* searches: sequential search, binary search
* sorts: insertion sort, quick sort, heap sort
* heaps: siftup, siftdown
* priority queues: initialize, insert, extract max
* order statistics: select
* all set algorithms operate on the array x.1 to x.n; there is
* no calling interface
*
* Originally published in Communications of the ACM, July 1985. Updated
* and republished by Addison-Wesley in "More Programming Pearls" in 1988.
*/

/* MAIN PROGRAM */

globals = 'bign smalln errcnt n x. searchname sortname pqmax'
bign = 12; smalln = 5; errcnt = 0
say "testing assert -- should fail"
call assert 1 = 0

say "testing select"
do n = 0 to bign
say " n=" n
call clearsubs
do i = 1 to n
call geninorder
call select i
call checkselect i
end
do i = 1 to n
call scramble
call select i
call checkselect i
end
call genequal
do i = 1 to n
call select i
call checkselect i
end
call checksubs
end

say "testing quick sort"
call testsort "qsort"
say "testing insertion sort"
call testsort "isort"
say "testing heap sort"
call testsort "hsort"

say "testing priority queues"
do m = 0 to bign
say " m=" m
call clearsubs
call pqinit m
do i = 1 to m
call pqinsert i
end
do i = m to 1 by -1
call assert pqextractmax() = i
end
call assert n = 0
call pqinit m
do i = m to 1 by -1
call pqinsert i
end
do i = m to 1 by -1
call assert pqextractmax() = i
end
call assert n = 0
call pqinit m
do i = 1 to m
call pqinsert 1
end
do i = m to 1 by -1
call assert pqextractmax() = 1
end
call assert n = 0
n = m
call checksubs
end

say "testing sequential search"
call testsearch "ssearch"
say "testing binary search"
call testsearch "bsearch"

say "total errors (1 expected):" errcnt
if errcnt > 1 then
say ">>>> TEST FAILED <<<<"
exit

/* TESTING ROUTINES */

assert: procedure expose (globals)
parse arg cond
if \cond then do
errcnt = errcnt + 1
say " >> assert failed <<"
end
return

checkselect: procedure expose (globals)
parse arg k
do i = 1 to k - 1
call assert x.i <= x.k
end
do i = k + 1 to n
call assert x.i >= x.k
end
return

checksort: procedure expose (globals)
do i = 1 to n - 1
iplus1 = i + 1
call assert x.i <= x.iplus1
end
return

checksubs: procedure expose (globals)
do i = 1 to n
drop x.i
end
/* assert x. is empty; not possible in rexx */
return

clearsubs: procedure expose (globals)
drop x.
return

genequal: procedure expose (globals)
do i = 1 to n
x.i = 1
end
return

geninorder: procedure expose (globals)
do i = 1 to n
x.i = i
end
return

scramble: procedure expose (globals)
do i = 1 to n
call swap i, random(i, n)
end
return

search: procedure expose (globals)
parse arg t
select
when searchname = "bsearch" then return bsearch(t)
when searchname = "ssearch" then return ssearch(t)
otherwise do
say "invalid search name"
call assert 1 = 0
return
end
end

sort: procedure expose (globals)
select
when sortname = "qsort" then call qsort 1, n
when sortname = "hsort" then call hsort
when sortname = "isort" then call isort
otherwise do
say "invalid sort name"
call assert 1 = 0
end
end
return

testsearch: procedure expose (globals)
parse arg searchname
do n = 0 to bign
say " n=" n
call clearsubs
call geninorder
do i = 1 to n
call assert search(i ) = i
call assert search(i - 0.5) = 0
call assert search(i + 0.5) = 0
end
call genequal
call assert search(0.5) = 0
if n > 0 then
call assert search(1) >= 1
call assert search(1) <= n
call assert search(1.5) = 0
call checksubs
end
return

testsort: procedure expose (globals)
parse arg sortname
say " pathological tests"
do n = 0 to bign
say " n=" n
call clearsubs
call geninorder
call sort
call checksort
do i = 1 to n/2
call swap i, n+1-i
end
call sort
call checksort
call genequal
call sort
call checksort
call checksubs
end
say " random tests"
nfac = 1
do n = 1 to smalln
say " n=" n
nfac = nfac * n
call clearsubs
call geninorder
do i = 1 to nfac
call scramble
call sort
call checksort
end
call checksubs
end
return

/* SET ALGORITHMS */

/* swap -- exchange x.i and x.j */
swap: procedure expose (globals)
parse arg i, j
t = x.i; x.i = x.j; x.j = t
return

/* select -- partition x. so k'th largest element is in x.k */
/* average time complexity of n */
/* worst-case time complexity of n * n if x.1 = ... = x.n */
select: procedure expose (globals)
parse arg k
l = 1
u = n
do while l < u
call swap l, random(l, u)
t = x.l
m = l
do i = l + 1 to u
if x.i < t then do
m = m + 1
call swap m, i
end
end
call swap l, m
if m <= k then l = m + 1
if m >= k then u = m - 1
end
return

/* qsort -- quick sort of x.l to x.u */
/* recursive; call initially by qsort(1,n) */
/* average time complexity of n log n */
/* worst-case time complexity of n * n if x.1 = ... = x.n */
qsort: procedure expose (globals)
parse arg l, u
if l < u then do
call swap l, random(l, u)
t = x.l
m = l
do i = l + 1 to u
if x.i < t then do
m = m + 1
call swap m, i
end
end
call swap l, m
call qsort l, m - 1
call qsort m + 1, u
end
return

/* isort -- insertion sort of x.1 to x.n */
/* average time complexity of n * n */
/* best-case time complexity of n when x.1 <= ... <= x.n */
isort: procedure expose (globals)
do i = 2 to n
do j = i to 2 by -1
jminus1 = j - 1
if x.jminus1 > x.j then
call swap jminus1, j
else
leave
end
end
return

/* siftup -- re-establish heap after adding element to end */
/* time complexity of log n */
siftup: procedure expose (globals)
parse arg l, u
i = u
do forever
if i <= l then leave
p = trunc(i / 2)
if x.p >= x.i then leave
call swap p, i
i = p
end
return

/* siftdown -- re-establish heap after extracting maximum */
/* time complexity of log n */
siftdown: procedure expose (globals)
parse arg l, u
i = l
do forever
c = 2 * i
if c > u then leave
cplus1 = c + 1
if cplus1 <= u then
if x.cplus1 > x.c then
c = cplus1
if x.i >= x.c then leave
call swap c, i
i = c
end
return

/* hsort -- heap sort of x.1 to x.n */
/* time complexity of n log n */
hsort: procedure expose (globals)
do i = trunc(n / 2) to 1 by -1
call siftdown i, n
end
do i = n to 2 by -1
call swap 1, i
call siftdown 1, i - 1
end
return

/* pqinit -- initialize priority queue */
/* time complexity of 1 */
pqinit: procedure expose (globals)
parse arg pqmax
n = 0
return

/* pqinsert -- insert t into priority queue */
/* time complexity of log n */
pqinsert: procedure expose (globals)
parse arg t
call assert n < pqmax
n = n + 1
x.n = t
call siftup 1, n
return

/* pqextractmax -- delete and return value of */
/* maximum element in priority queue */
/* assumes priority queue is non-empty */
/* time complexity of log n */
pqextractmax: procedure expose (globals)
call assert n >= 1
t = x.1
x.1 = x.n
n = n - 1
call siftdown 1, n
return t

/* ssearch -- sequential search for t in x.1 to x.n */
/* returns position of t in x, or 0 if t not in x */
/* returns first of multiple identical items */
/* time complexity of n */
ssearch: procedure expose (globals)
parse arg t
do i = 1 to n
if x.i = t then return i
end
return 0

/* bsearch -- binary search for t in sorted x.1 to x.n */
/* assumes x.1 <= x.2 <= x.i <= x.n for all 1 <= i <= n */
/* returns position of t in x, or 0 if t not in x */
/* returns any of multiple identical items */
/* time complexity of log n */
bsearch: procedure expose (globals)
parse arg t
l = 1; u = n
do while l <= u
m = trunc((l + u) / 2)
select
when x.m < t then l = m + 1
when x.m > t then u = m - 1
otherwise /* x.m = t */ return m
end
end
return 0
--
Phil Bewig ... pbe...@netcom.COM

pmu...@vnet.ibm.com

unread,
Aug 23, 1993, 2:01:50 PM8/23/93
to
In <pbewigCC...@netcom.com>, pbe...@netcom.com (Phil Bewig) writes:
>
>Critique of Rexx, and a procedure library

Nice review, especially for folks not already familiar with REXX.

A few notes:

Many of wishes - call by reference, computed tail values, etc. have been
expressed by IBMers for years. There is work going on to architect this
stuff out, but who can say when it will appear in a product (and don't
ask me, because I am in NO way involved).

wrt: pass by reference. REXX level 4.0 includes kind-of-a way to call
by reference. You can do a "procedure expose (varList)" after a label.
The value of varList is used as a list of variable names to expose.
Below is a sample of it's use. Obviously not all that great (you have
to set the 'varList' variable before calling the function). In my example,
I hide this by invoking a 'shadow' function.

====================================================================
/*------------------------------------------------------------------
* arg.cmd :
*------------------------------------------------------------------
* 08-23-93 originally by Patrick J. Mueller
*------------------------------------------------------------------*/

a.0 = 3
do i = 1 to a.0
a.i = i * i
end

rc = copyArray("a.","b.")

do i = 1 to b.0
say b.i
end

rc = copyArray("b.","c.")

do i = 1 to c.0
say c.i
end

exit

copyArray:
arrays = arg(1) arg(2)
return copyArray2()

copyArray2: procedure expose (arrays)
sArray = word(arrays,1)
dArray = word(arrays,2)

rc = value(dArray"0",value(sArray"0"))
do i = 1 to value(sArray"0")
rc = value(dArray"i",value(sArray"i"))
end

return ""
====================================================================

I've also seen a neat trick for computed tail values. It involves
creating a function with the same name as the stem variable, including
the "." suffix. Here's an example:

====================================================================
/*------------------------------------------------------------------
* inc.cmd :
*------------------------------------------------------------------
* 08-23-93 originally by Patrick J. Mueller
*------------------------------------------------------------------*/

/*------------------------------------------------------------------
* easier incremental list
*------------------------------------------------------------------*/
list.0 = 0

do i = 1 to 3
list.0 = list.0 + 1
rc = list.(list.0,i*i)
end

do i = 1 to list.0
say list.i
end

/*------------------------------------------------------------------
* compute fibonacci numbers
*------------------------------------------------------------------*/
list.1 = 1
list.2 = 1

do i = 3 to 10
list.i = list.(i-1) + list.(i-2)
end

do i = 1 to 10
say list.i
end

exit

/*------------------------------------------------------------------
* function to access and set stemmed variable with computed index
*------------------------------------------------------------------*/
list. : procedure expose list.
index = arg(1)
value = arg(2)

if (arg() = 1) then
return list.index

list.index = value
return value
====================================================================

Patrick Mueller addr: pmu...@vnet.ibm.com (node carvm3)
IBM PRGS Cary, North Carolina phone: 919-469-7242 (tie-line 883)

Dave Gomberg

unread,
Aug 23, 1993, 2:35:22 PM8/23/93
to
Patrick, your function example makes me think of the following enhancement
to REXX semantics that solves LOTS of problems:

function_name(arg_list)=expression

causes invocation of function_name||'PV'
with the argument list VALUE(expression),arg_list

Now any function may also operate as a pseudo-variable if it wishes to,
and the implementation doesn't need to worry about what a pseudo-variable
is. Hmmmm.

Dave Gomberg, role model for those who don't ask much in their fantasy lives.
GOMBERG@UCSFVM Internet node UCSFVM.UCSF.EDU fax-> (415)731-7797

Ian Collier

unread,
Aug 24, 1993, 12:13:46 PM8/24/93
to
In article <pbewigCC...@netcom.com>, pbe...@netcom.com (Phil Bewig) wrote:
> The most obvious problem is the
>prohibition of expressions in the tail of a compound
>variable: "x.i+1" parses as "(x.i)+1" and "x.(i+1)" is
>illegal, and must be written as "iplus1=i+1; x.iplus1"

I agree this is a pain sometimes (which is why I allowed it in REXX/imc).

> There are no records or structs, so a programmer
>must resort to the old fortran trick of parallel arrays.

I'm not entirely sure what you mean by "no records or structs", but what
you can do is write

book.1._author = "M. F. Cowlishaw"
book.1._title = "The REXX Language, a practical approach to programming"
book.2._author = "A. S. Rudd"
book.2._title = "Practical Usage of REXX"
<etc>
say book.i._title "by" book.i._author

It looks like a struct to me. :-) [there's nothing special about the
underscore characters, but that's one way of ensuring that the variables
_author and _title do not get re-used. Another way is to make them into
constant symbols such as 1author and 1title].

>All elements in a conditional expression are evaluated,
>preventing the "short-circuit" evaluation of conditions as
>in C;

This is occasionally a problem for me. Sometimes you can get around it by
replacing "&" with "then if". If the thing on the right-hand side of an "|"
is really slow, then you could write "or('a','b')" instead of "a|b" where
or: parse arg a,b
interpret "if" a "then return 1"
interpret "return" b
but that's rather a hack. :-)

> in most other languages it
>would be possible to make the name of the compound variable
>to be sorted a parameter to the sort procedure.

REXX/imc allows:

parse arg stemname
procedure expose (stemname)

although getting and assigning the values of this stem is rather difficult,
needing either an INTERPRET or a call to VALUE. Note that the argument must
include the final dot of the stem name.

Uni-REXX and Regina allow:

interpret 'procedure expose' arg(1)

Neither of these is "correct" behaviour, because the ruling on "procedure"
is that it should be the first instruction executed on entry to a subroutine
(and the "interpret" is counted). This rule did not always exist, and
personally I think that there are valid reasons for relaxing it, the above
being one of them. Adding extra code just to try and prevent this is not
high on my list of priorities (though interestingly, REXX/imc does not
allow the interpret trick because the interpeted string is regarded as
being in a separate level).

>There are no static variables, so any variable which is
>local to a procedure but must retain its value between calls
>of the procedure must be global.

> Any variable which
>is to be initialized must be global, because otherwise its
>scope is only the procedure in which it is initialized.

This is one of the things argued in a recent thread on "software
engineering". Basically, we agree with you...

>One problem which sounds simple but has the capacity to do
>great harm is the lack of any syntactic limits on a
>procedure.

I don't see precisely whay you mean by "syntactic limits". Accidental
fall-through is a problem in some other languages, whereas in others you
are forced to end the procedure with an END or a brace. If you want,
you can type "return" at the end of each procedure as a substitute for
this END or brace. Perhaps you wanted the interpreter to enforce such
practice. I don't think this is realistic given the current syntax.
Historically speaking, it is also a problem that the interpreter may
not read in the entire program before executing it, and so it would
never be able to discover the missing brace or whatever.

> consider this scenario: during
>program development or maintenance, a procedure which is a
>large "if ... else if ... else" chain, with each alternative
>in the chain processing its own return, is modified so that
>none of the alternatives is selected,

Ah well, if you had used the correct construction (namely "select") in the
first place, this wouldn't have happened. Unlike an if-elseif chain, a
select is not allowed to fall through without executing any instructions.

>Although a program can create an arbitrary number of tails
>for a single compound variable, Rexx makes no provision to
>iterate over all of the tails, as in the "for (i in x)" loop
>of awk.

Indeed, this has been seen here in comp.lang.rexx several times.

Ian Collier
Ian.C...@prg.ox.ac.uk | i...@ecs.ox.ac.uk

Ian Collier

unread,
Aug 24, 1993, 12:19:19 PM8/24/93
to
In article <REXXLIST%9308231...@UGA.CC.UGA.EDU>, Dave Gomberg <GOM...@UCSFVM.BITNET> wrote:

>function_name(arg_list)=expression
>causes invocation of function_name||'PV'
>with the argument list VALUE(expression),arg_list

Excuse me if I missed something, but why don't you just write this?:

call function_namepv expression,arg_list

It will save a lot of work implementing a marginally useful new feature.

BTW your "value" above is not the same as the built-in function VALUE()
because the latter only does variables (not whole expressions). You
should try to pick unique names for your functions. :-)

Ian Collier
Ian.C...@prg.ox.ac.uk | i...@ecs.ox.ac.uk

Dave Gomberg

unread,
Aug 24, 1993, 12:39:50 PM8/24/93
to
On Tue, 24 Aug 1993 16:19:19 GMT Ian Collier said:
>In article <REXXLIST%9308231...@UGA.CC.UGA.EDU>, Dave Gomberg
><GOM...@UCSFVM.BITNET> wrote:
>
>>function_name(arg_list)=expression
>>causes invocation of function_name||'PV'
>>with the argument list VALUE(expression),arg_list
>
>Excuse me if I missed something, but why don't you just write this?:
>
>call function_namepv expression,arg_list

Because I wish to permit x.(I+1) = x.I + x.(I-1)

>BTW your "value" above is not the same as the built-in function VALUE()
>because the latter only does variables (not whole expressions). You
>should try to pick unique names for your functions. :-)

It is the same as CMS VALUE(), which does permit expressions according
to the help file.

Dave Gomberg

unread,
Aug 24, 1993, 12:44:07 PM8/24/93
to
On Tue, 24 Aug 1993 16:19:19 GMT Ian Collier said:
>In article <REXXLIST%9308231...@UGA.CC.UGA.EDU>, Dave Gomberg
><GOM...@UCSFVM.BITNET> wrote:
>
>>function_name(arg_list)=expression
>>causes invocation of function_name||'PV'
>>with the argument list VALUE(expression),arg_list
>
>Excuse me if I missed something, but why don't you just write this?:
>
>call function_namepv expression,arg_list

You also get SUBSTR(A,5,3)="ABC" with only that tiny language change.

Horst Kiehl

unread,
Aug 25, 1993, 6:08:50 AM8/25/93
to
In article <1993Aug24.1...@msc7.comlab.ox.ac.uk>,
i...@comlab.ox.ac.uk (Ian Collier) writes:

>In article <pbewigCC...@netcom.com>, pbe...@netcom.com (Phil Bewig) wrote:

>>All elements in a conditional expression are evaluated,
>>preventing the "short-circuit" evaluation of conditions as
>>in C;
>

> you could write "or('a','b')" instead of "a|b" where
> or: parse arg a,b
> interpret "if" a "then return 1"
> interpret "return" b

Or:

or: interpret "if" arg(1) "then return 1"
interpret "return" arg(2)

This way you avoid using variables.

Horst
- - - - - - - - - - - - - - - - - - - - - - -
Horst Kiehl - Internet h.p....@kfa-juelich.de

Ian Collier

unread,
Aug 25, 1993, 9:54:40 AM8/25/93
to
In article <REXXLIST%9308241...@UGA.CC.UGA.EDU>, Dave Gomberg <GOM...@UCSFVM.BITNET> wrote:
>On Tue, 24 Aug 1993 16:19:19 GMT Ian Collier said:
>>Excuse me if I missed something, but why don't you just write this?:
>>call function_namepv expression,arg_list

>Because I wish to permit x.(I+1) = x.I + x.(I-1)

>You also get SUBSTR(A,5,3)="ABC" with only that tiny language change.

Hmmm, I'm still not exactly happy with it, though I can't think of any real
objections at the moment. There is one small one, though: the names of your
functions will have to be restricted to avoid ambiguities like
say(6) = 7
which is at odds with the REXX philosophy of no reserved words.

>>BTW your "value" above is not the same as the built-in function VALUE()

>It is the same as CMS VALUE(), which does permit expressions according
>to the help file.

Are you *sure*? I seem to remember (years ago) thinking that it did and
finding that it didn't. Note that it's OK for the help file to say:

value(expression)

The expression is evaluated and...

because that's normal for a function call. What you want is for the
expression to result in an expression which will be evaluated, and I
still don't believe that it will be. The expression should result in
a symbol name whose value will be returned.

If you still think the help file allows value() to evaluate expressions,
try it out. So far, three interpreters (and the draft ANSI standard) agree
with me and none with you... ;-)

Ian Collier
Ian.C...@prg.ox.ac.uk | i...@ecs.ox.ac.uk

Dave Gomberg

unread,
Aug 25, 1993, 12:23:03 PM8/25/93
to
On Wed, 25 Aug 1993 13:54:40 GMT Ian Collier said:
>In article <REXXLIST%9308241...@UGA.CC.UGA.EDU>, Dave Gomberg
><GOM...@UCSFVM.BITNET> wrote:
>>On Tue, 24 Aug 1993 16:19:19 GMT Ian Collier said:
>>>Excuse me if I missed something, but why don't you just write this?:
>>>call function_namepv expression,arg_list
>
>>Because I wish to permit x.(I+1) = x.I + x.(I-1)
>>You also get SUBSTR(A,5,3)="ABC" with only that tiny language change.
>
>Hmmm, I'm still not exactly happy with it, though I can't think of any real
>objections at the moment. There is one small one, though: the names of your
>functions will have to be restricted to avoid ambiguities like
> say(6) = 7
>which is at odds with the REXX philosophy of no reserved words.

As I see it right now your example is an error (since say(6) has the form
of a function reference which cannot appear on the LHS), but it works in
CMS as SAY (6)=7. I think it should be an error now, and in the expanded
definition, it should be a function invocation.

>>>BTW your "value" above is not the same as the built-in function VALUE()
>
>>It is the same as CMS VALUE(), which does permit expressions according
>>to the help file.
>
>Are you *sure*? I seem to remember (years ago) thinking that it did and
>finding that it didn't. Note that it's OK for the help file to say:

Well it works now. I tried it. abc=1;say value('a'||'b'||'c')
says 1.

>If you still think the help file allows value() to evaluate expressions,
>try it out. So far, three interpreters (and the draft ANSI standard) agree
>with me and none with you... ;-)

Now it's 3:1. Dave

>Ian.C...@prg.ox.ac.uk | i...@ecs.ox.ac.uk

F. Scott Ophof

unread,
Aug 25, 1993, 11:37:53 AM8/25/93
to
On Wed, 25 Aug 1993 06:08:50 -0400 Horst Kiehl said:
>i...@comlab.ox.ac.uk (Ian Collier) writes:
>>pbe...@netcom.com (Phil Bewig) wrote:
>>>All elements in a conditional expression are evaluated,
>>>preventing the "short-circuit" evaluation of conditions as
>>>in C;

I'm curious as to the reason for not "short-circuiting" the
evaluation.


>Or:
> or: interpret "if" arg(1) "then return 1"
> interpret "return" arg(2)
>This way you avoid using variables.

IMHO the whole idea of INTERPRET *plus* the invocation of a function
doesn't seem exactly cheap resource-wise; "a" must be very 'cheap'
and "b" quite 'expensive' to offset the 'costs'... (?)

The following provides for more than just "a|b", and simply skips
unspecified or blank-only arguments.

/* */
Or: Procedure
Do I=1 to arg()
If strip(arg(I))='' then iterate
Interpret "If" arg(I) "then return 1"
End I
Return 0


Regards.
$$\
"We now present the conclusion of ... The Never-ending Story"

Rodney A Sparapani

unread,
Aug 25, 1993, 2:49:00 PM8/25/93
to
In article <1993Aug25.1...@msc7.comlab.ox.ac.uk> i...@comlab.ox.ac.uk (Ian Collier) writes:
>In article <REXXLIST%9308241...@UGA.CC.UGA.EDU>, Dave Gomberg <GOM...@UCSFVM.BITNET> wrote:
>>On Tue, 24 Aug 1993 16:19:19 GMT Ian Collier said:
>>You also get SUBSTR(A,5,3)="ABC" with only that tiny language change.

This would be nice and in keeping with REXX's Fourth (Fifth?) generation flavor.
However, the following would produce:

> say(6) = 7

0 meaning False.

>which is at odds with the REXX philosophy of no reserved words.

I have heard this many times, but I don't see what reserved words
(or non-reserved words) have to do with it: the intention of say(6)=7 is
ambiguous. If you reserved the word "say" then you could not
use it for any other purpose, which would be contrary to REXX philosophy,
but so would trying to make a function named "say" wouldn't it?

>>It is the same as CMS VALUE(), which does permit expressions according

>Are you *sure*? I seem to remember (years ago) thinking that it did and
>finding that it didn't. Note that it's OK for the help file to say:

>If you still think the help file allows value() to evaluate expressions,
>try it out. So far, three interpreters (and the draft ANSI standard) agree
>with me and none with you... ;-)

say value(7>6)

returns 1(This is under CMS/REXX v.5, so not a new feature).

Is this what you mean by an expression?
--

Rodney Sparapani Great Multi-word Names for new Seattle bands
Trilogy Consulting, Corp. Right Wing Death Squad Pontius Pilot
courtesy of Monsanto Agricultural Co. Peter, the Love Puppet

Dave Gomberg

unread,
Aug 25, 1993, 2:58:48 PM8/25/93
to
On Wed, 25 Aug 1993 18:49:00 GMT Rodney A Sparapani said:
>However, the following would produce:
>
>> say(6) = 7
>
>0 meaning False.

This would only be true if we fail to require that an instruction name meant
to be interpreted as an instance of that instruc tion be followed by a blank.
Such a restriction seems eminently sensible to me. Does anyone really want
to write PARSEVAR meaning to have a parse instruction of the VAR persuasion?

>>which is at odds with the REXX philosophy of no reserved words.

What philosophy of no reserved words? Try DO WHILE=3; SAY Hi; END
sometime, for a real thrill. There are three possible interpretations, and
the one I get in CMS I would call the least likely.

Bernie Cosell

unread,
Aug 25, 1993, 10:23:38 PM8/25/93
to
In article <7...@zam103.zam.kfa-juelich.de>, Horst Kiehl writes:

} In article <1993Aug24.1...@msc7.comlab.ox.ac.uk>,
} i...@comlab.ox.ac.uk (Ian Collier) writes:
}

} >In article <pbewigCC...@netcom.com>, pbe...@netcom.com (Phil Bewig) wrote:
}
} >>All elements in a conditional expression are evaluated,
} >>preventing the "short-circuit" evaluation of conditions as
} >>in C;
} >

} > you could write "or('a','b')" instead of "a|b" where
} > or: parse arg a,b
} > interpret "if" a "then return 1"
} > interpret "return" b
}

} Or:
}
} or: interpret "if" arg(1) "then return 1"
} interpret "return" arg(2)

On the other hand, if you're worried about efficiency, doing an
'interpret' is *guaranteed* to be a loser [I shudder to think that
folk would seriously put an 'interpret' into a time-critical inner
loop...] It'd be a lot faster to use a little procedure. Instead
of
if a | b then <code>

you can do
if a then call codeproc
else if b then call codeproc
....

codeproc:
<code>
return

/Bernie\
--
Bernie Cosell cos...@world.std.com
Fantasy Farm Fibers, Pearisburg, VA (703) 921-2358

Ian Collier

unread,
Aug 27, 1993, 9:14:23 AM8/27/93
to
Rodney A Sparapani and Dave Gomberg posted similar replies to my earlier
posting.
In article <REXXLIST%9308251...@UGA.CC.UGA.EDU>, Dave Gomberg <GOM...@UCSFVM.BITNET> wrote:
>> say(6) = 7

>As I see it right now your example is an error (since say(6) has the form
>of a function reference which cannot appear on the LHS), but it works in
>CMS as SAY (6)=7.

>definition, it should be a function invocation.

There is nothing preventing "function()=value" at present as far as I
can see. It is an expression which yields 0 or 1 and is passed to the
environment. At present my example "say(6)=7" should evaluate "(6)=7"
and say the result.

>>>>BTW your "value" above is not the same as the built-in function VALUE()

>Well it works now. I tried it. abc=1;say value('a'||'b'||'c')
>says 1.

As I explained in detail, this is not a valid use of the function value()
to evaluate an expression. The expression 'a'||'b'||'c' is evaluated before
value() even sees it, so value() itself is only giving the value of the
variable "abc".

Try: expression='1+2'; say value(expression)

This is the context in which you originally wrote "VALUE()", and it is an
incorrect use. Here is your original text:

>function_name(arg_list)=expression
>causes invocation of function_name||'PV'
>with the argument list VALUE(expression),arg_list

imc

Steve Bacher

unread,
Aug 27, 1993, 11:08:00 AM8/27/93
to
(I had to change the thread title. It was only the original posting
that was LONG, not the followups.)

In article <1993Aug25.1...@tin.monsanto.com>,


ras...@asdrs1.monsanto.com (Rodney A Sparapani) writes:

>say value(7>6)
>
>returns 1(This is under CMS/REXX v.5, so not a new feature).

That doesn't demonstrate anything, since 7>6 gets evalated by the
REXX interpreter before it gets passed to the VALUE function.

More interesting would be what

say value("7>6")

returns. On TSO/REXX it generates an "Incorrect call to routine"
error because 7>6 is not a valid variable name.

(On the other hand, value(7>6) also ought to return an error,
because 1 is not a valid symbol name. The fact that it doesn't
seems to point up a bug or oversight, unless I'm missing something.)

In Regina, value(7>6) returns 1, and value("7>6") returns 7>6.
At least it's consistent, which is superior to what TSO/REXX does.

--
Steve Bacher (Batchman) Draper Laboratory
Internet: s...@draper.com Cambridge, MA, USA

Ian Collier

unread,
Aug 27, 1993, 9:34:30 AM8/27/93
to
In article <REXXLIST%9308251...@UGA.CC.UGA.EDU>, Dave Gomberg <GOM...@UCSFVM.BITNET> wrote:
>>> say(6) = 7
>>0 meaning False.

>This would only be true if we fail to require that an instruction name meant
>to be interpreted as an instance of that instruc tion be followed by a blank.
>Such a restriction seems eminently sensible to me. Does anyone really want
>to write PARSEVAR meaning to have a parse instruction of the VAR persuasion?

No. "parsevar" is a single token, whereas "parse var" is two tokens.
That's not to say that a space is required. It is perfectly possible to
write "if(x==3)then say'hello'", just as it is possible to say "nop;", and
the distinction between tokens is equally clear. It would be too pedantic
to require a space between "if" and "(x==3)", or between "nop" and ";", in
my opinion.

>>>which is at odds with the REXX philosophy of no reserved words.

>What philosophy of no reserved words? Try DO WHILE=3; SAY Hi; END
>sometime, for a real thrill.

The word "while" in this instance is a variable, because it is not a
reserved word. That's the philosophy of no reserved words for you.
(Aside: Uni-REXX doesn't agree...)

In "say(6)=7", there are various alternative interpretations (in a situation
where pseudovariables have been implemented):

1. "say" is not a reserved word because it is not followed by a space.
As I said, I think this borders on the pedantic, and I reject this
option.
2. "say" is not a reserved word because, as we can clearly see, it is the
name of a function which is on the left-hand side of '='. I reject
this option because the lexical analyser which decides whether or not
"say" is a keyword has to do an enormous amount of lookahead in order
to find the '=' or lack thereof. It may also become difficult for a
human to tell the difference, if lines get too long and complex.
3. "say" is a reserved word, so the instruction says "0". I reject this
option because it has never before been a problem to name a function
"say", and nor should it be a problem.

Now, since I seem to have rejected all of the above interpretations, it
seems that I have no option but to reject the idea of giving a meaning
to functions on the left-hand side of '='.

Ian Collier
Ian.C...@prg.ox.ac.uk | i...@ecs.ox.ac.uk

Dave Gomberg

unread,
Aug 27, 1993, 10:59:49 AM8/27/93
to
On Fri, 27 Aug 1993 13:34:30 GMT Ian Collier said:
>>>>which is at odds with the REXX philosophy of no reserved words.
>
>>What philosophy of no reserved words? Try DO WHILE=3; SAY Hi; END
>>sometime, for a real thrill.
>
>The word "while" in this instance is a variable, because it is not a
>reserved word. That's the philosophy of no reserved words for you.
>(Aside: Uni-REXX doesn't agree...)

Wrong. If WHILE were read as a variable, then WHILE=3 would have been 0 and
0 iterations would have occurred. If you have a CMS implementation, try it.

Peter A Kronenberg

unread,
Aug 27, 1993, 11:15:24 AM8/27/93
to
On Fri, 27 Aug 1993 07:59:49 PDT Dave Gomberg said:
>Wrong. If WHILE were read as a variable, then WHILE=3 would have been 0 and
>0 iterations would have occurred. If you have a CMS implementation, try it.
>
>Dave Gomberg, role model for those who don't ask much in their fantasy lives.
>GOMBERG@UCSFVM Internet node UCSFVM.UCSF.EDU fax-> (415)731-7797

WHILE *is* a variable in this case. WHILE=3 is an assignment
which initializes the variable to 3. The loop is an infinite
loop with the value of While increasing by one at each iteration.

Peter

Dave Gomberg

unread,
Aug 27, 1993, 11:21:55 AM8/27/93
to
Peter, thanks for pointing out that interpretation.

Interestingly enough, DO (WHILE=3) says invalid expression. Why isn't
this just DO 0?

Peter A Kronenberg

unread,
Aug 27, 1993, 11:40:11 AM8/27/93
to
On Fri, 27 Aug 1993 08:21:55 PDT Dave Gomberg said:
>Peter, thanks for pointing out that interpretation.

It's not just my interpretation. It's CMS's.

>Interestingly enough, DO (WHILE=3) says invalid expression. Why isn't
>this just DO 0?

The syntax of the DO command is DO repetitor and one of the
choices for repetitor is name=expri TO exprt BY exprb FOR exprf.
For example, DO i = 1 TO 10 BY 2

I left out the FOR exprf expression. expri is the intial
assignment, in our case, WHILE=3. The book specifically says that
if exprt is omitted (TO exprt), the loop runs
indefinitely unless some other condition terminates it.

---
Later --- I think you have a point. In addition to DO repetitor,
DO can also be followed by an expression which must result in
a number >= 0. DO 0 certainly works so I guess DO (while=3)
should also be interpreted as DO 0. I guess it's a bug.

Peter

Brent S Noorda

unread,
Aug 27, 1993, 2:11:11 PM8/27/93
to
I tried REXX for a while after I got OS/2, and I was won over by
the ability it immediately gave me for enhancing my environment and
for automating my tasks. It was great to have that language right
there where it was part of my environment and I could use it all the
time, without having to compile a complicated program or be limited
by the tiny batch lanaguage.

But in the end I was not won over by REXX itself, for many of the
reasons that results in critical critiques of Rexx.

So I created created a scripting/batch/programming language that I
call Cmm ('C' minus minus) which is based on the C language. CEnvi
is a Cmm interpreter that my company, Nombas, sells as shareware and
gives many of the benefits of Rexx but with a language that was easier
for me to use and is also easier for others. I'm not saying that
everyone would rather use Cmm than Rexx; whatever floats your boat
is OK by me.

If you'd like to try this $38 alternative to Rexx, then you can receive it
via anonymous ftp from world.std.com in the pub directory. Each version
comes with lotta documentation and sample Cmm files.
CEnvi for OS/2: cenvi21.zip
CEnvi for DOS: cenvid1.zip
CEnvi for Windows: cenviw1.zip

Or mail me and we'll work out a way for you to try this shareware.

b...@world.std.com

2138...@msu.bitnet

unread,
Aug 27, 1993, 1:58:20 PM8/27/93
to
>On Fri, 27 Aug 1993 08:21:55 PDT Dave Gomberg said:
>>Peter, thanks for pointing out that interpretation.
>
>It's not just my interpretation. It's CMS's.
>
>>Interestingly enough, DO (WHILE=3) says invalid expression. Why isn't
>>this just DO 0?
>
>---
>Later --- I think you have a point. In addition to DO repetitor,
>DO can also be followed by an expression which must result in
>a number >= 0. DO 0 certainly works so I guess DO (while=3)
>should also be interpreted as DO 0. I guess it's a bug.
>
>Peter

According the VM/XA SP System Product Interpreter manual, on page 28:

"The sub-keywords TO, BY, FOR, WHILE and UNTIL are reserved within a
DO instruction, in that they cannot name variables in the expression(s) but
they may be used as the name of the control variable."

In the case of "DO WHILE=3", WHILE is used as the name of the control variable,
so there is no problem. In "DO (WHILE=3)", WHILE is not the name of the
control variable, so it is reserved as a sub-keywword. When considered a
sub-keyword in this context, it results in a syntax error.

Paul S. Wolberg Internet: 2138...@ibm.cl.msu.edu
1322 Oakridge Ave., Apt. 105 BITNET: 21387psw@MSU
E. Lansing, MI 48823 Voice: H: 517-332-2173
W: 517-337-4949

Peter A Kronenberg

unread,
Aug 27, 1993, 2:23:49 PM8/27/93
to
On Fri, 27 Aug 1993 13:58:20 EDT <21387PSW%MSU.B...@vm.gmd.de> said:
>According the VM/XA SP System Product Interpreter manual, on page 28:
>
>"The sub-keywords TO, BY, FOR, WHILE and UNTIL are reserved within a
>DO instruction, in that they cannot name variables in the expression(s) but
>they may be used as the name of the control variable."
>
>In the case of "DO WHILE=3", WHILE is used as the name of the control variable,
>so there is no problem. In "DO (WHILE=3)", WHILE is not the name of the
>control variable, so it is reserved as a sub-keywword. When considered a
>sub-keyword in this context, it results in a syntax error.

Yup, you're exactly right. Do (WHILE=3) gives an
error, but Do (WHILEX=3) does not.

Peter

Steve Bacher

unread,
Aug 27, 1993, 8:03:00 PM8/27/93
to
In article <1993Aug27....@msc8.comlab.ox.ac.uk>,
i...@comlab.ox.ac.uk (Ian Collier) writes:

>In "say(6)=7", there are various alternative interpretations (in a situation
>where pseudovariables have been implemented):
>
> 1. "say" is not a reserved word because it is not followed by a space.
> As I said, I think this borders on the pedantic, and I reject this
> option.
> 2. "say" is not a reserved word because, as we can clearly see, it is the
> name of a function which is on the left-hand side of '='. I reject
> this option because the lexical analyser which decides whether or not
> "say" is a keyword has to do an enormous amount of lookahead in order
> to find the '=' or lack thereof. It may also become difficult for a
> human to tell the difference, if lines get too long and complex.

Not only that, but it should be perfectly OK to have

say "Did you know that the value of 1e2 = 1 is..."
say 1e2 = 1
say "How about that?"

> 3. "say" is a reserved word, so the instruction says "0". I reject this
> option because it has never before been a problem to name a function
> "say", and nor should it be a problem.


>Now, since I seem to have rejected all of the above interpretations, it
>seems that I have no option but to reject the idea of giving a meaning
>to functions on the left-hand side of '='.

But by rejecting all those options, you have yet another
unacceptable conclusion: say(6) = 7 is illegal. Saying that
implies that either:

say (6) = 7

is illegal - and I reject that because making it illegal requires that
noxious equal-sign lookahead you rejected in (2) - or

say (6) = 7

is legal, which means that it's different from the illegal say(6) = 7,
which means we're being pedantic about spaces, which you rejected.

On the other hand, there are circumstances in which the space between
an identifier and a left parenthesis is significant in REXX, and ANSI
accepts this. So a bit of pedantry is unavoidable.

This forces me to conclude that the only reasonable interpretation is:

say(6) = 7 is a (not-in-the-language-yet) pseudofunction invocation
say (6) = 7 is a call to SAY passing it a boolean expression result

Now, what about if(x==3) and all that?

Left as an exercise for the reader...

Roger Deschner

unread,
Aug 27, 1993, 11:31:30 PM8/27/93
to
Here are some real reserved words in Rexx: x, b. Whatever you do, do not
use x or b as variable names. Oh, the simple "x = x + 1" assignment will
work fine, but you will get into real trouble because of the Rexx syntax
for hex and binary strings. The following example applies for either x
or b:

x = 'ZZ'
a = '10af'x
SAY a

You might think you'd get the string '10afZZ', but you don't!

And just another plug for SELECT-WHEN-OTHERWISE constructs as being
vastly superior to cascading IF THEN...IF THEN...IF THEN constructs. Not
only are they MUCH easier to read, but they are also, as has been noted,
much safer in limiting the scope of execution.

In CMS Rexx, we have two forms of global "Fortran Common" values - as of
CMS9, we can use the VALUE function to access CMS GLOBALV data (I think
UniREXX does this too), and we can also access any of our parent
generations' Rexx variable pools throguh the EXECCOMM interface. CMS
Pipelines (a truly cool thing) gives the Rexx programmer an easy way to
access the parent's variable pool via this EXECCOMM interface.

Dave Gomberg

unread,
Aug 28, 1993, 1:35:04 PM8/28/93
to
Wait, you guys have lost a major issue. There is in general in the
language already an enormous difference between "a(3)" and "a (3)".
All I am suggesting is that it should not matter whether a is on the
RHS or LHS. Nothing I said required any change in the meaning of
SAY(6)=7. That is a say instruction now and would remain one. I am
suggesting changing the interpretation of SUBSTR(A,3,3)='ABC' which
now is a logical, converted to 0 or 1 and passed to the environment
and which I suggest should become a function invocation.

Steve Bacher

unread,
Aug 28, 1993, 3:30:00 PM8/28/93
to
In article <REXXLIST%9308281...@UGA.CC.UGA.EDU>,
Dave Gomberg <GOM...@UCSFVM.BITNET> writes:

>Wait, you guys have lost a major issue. There is in general in the
>language already an enormous difference between "a(3)" and "a (3)".

I don't think I lost sight of that issue...

>All I am suggesting is that it should not matter whether a is on the
>RHS or LHS.

For the purpose of the space or lack thereof, I probably agree.

>Nothing I said required any change in the meaning of
>SAY(6)=7. That is a say instruction now and would remain one.

Now you've just contradicted yourself. If the space is significant,
then SAY(6)=7 is quite different from SAY (6)=7. The latter is clearly
a SAY instruction, but the former, by your logic, should be a
pseudofunction invocation.

>I am
>suggesting changing the interpretation of SUBSTR(A,3,3)='ABC' which
>now is a logical, converted to 0 or 1 and passed to the environment
>and which I suggest should become a function invocation.

Yes, but if this is to be a general syntactical phenomenon, then you
can't treat SAY (or IF, or WHILE) differently.

Jack Hamilton

unread,
Aug 28, 1993, 2:22:42 PM8/28/93
to
Dave Gomberg <GOM...@UCSFVM.BITNET> wrote:

<deleted stuff>

>Dave Gomberg, role model for those who don't ask much in their fantasy lives.
>GOMBERG@UCSFVM Internet node UCSFVM.UCSF.EDU fax-> (415)731-7797

Are you the same Dave Gomberg who has been mentioned on the radio show
"West Coast Weekend", and did you recently have a letter published in
"Verbatim: The Language Quarterly"?

Perhaps (re your signature) you're busy enough not to need a fantasy life.


--

------------------------------------------------------------------------
Jack Hamilton j...@netcom.com kd6ttl@n0ary.#nocal.ca.us.na packet
Post Office Box Box 281107 San Francisco, California 94128 USA

Dave Gomberg

unread,
Aug 28, 1993, 4:01:15 PM8/28/93
to
On Sat, 28 Aug 1993 19:30:00 GMT Steve Bacher said:
>>Nothing I said required any change in the meaning of
>>SAY(6)=7. That is a say instruction now and would remain one.
>
>Now you've just contradicted yourself. If the space is significant,
>then SAY(6)=7 is quite different from SAY (6)=7. The latter is clearly
>a SAY instruction, but the former, by your logic, should be a
>pseudofunction invocation.

I am saying that something with the form of an assignment, but which is
not an assignment because the LHS is of the form symbol(var_list) should
be considered a function invocation. SAY(6)=7 is not of the form of an
assignment, it is of the form of a say instruction. Hence it does not
satisfy the hypothesis of the proposal.

>
>>I am
>>suggesting changing the interpretation of SUBSTR(A,3,3)='ABC' which
>>now is a logical, converted to 0 or 1 and passed to the environment
>>and which I suggest should become a function invocation.
>
>Yes, but if this is to be a general syntactical phenomenon, then you
>can't treat SAY (or IF, or WHILE) differently.

IF(3)=4 THEN SAY HI is not of the form of an assignment, it is
of the form of an IF instruction, and not any kind of assignment. Therefore
the hypothesis of the proposal above is not satified and the proposal does
not apply. One could see this as introducing
an ambiguity and resolving the ambiguity in favor of compatibility.
Is that clearer?

Stephen E. Bacher

unread,
Aug 28, 1993, 4:43:22 PM8/28/93
to
Dave Gomberg writes:

>I am saying that something with the form of an assignment, but which is
>not an assignment because the LHS is of the form symbol(var_list) should
>be considered a function invocation. SAY(6)=7 is not of the form of an
>assignment, it is of the form of a say instruction. Hence it does not
>satisfy the hypothesis of the proposal.

Oh, then you mean that

SAY(X) = 7

is in the form of an assignment and therefore is a pseudofunction, but

SAY(6) = 7

is not, and therefore is a SAY instruction. Which leads one to conclude

SAY(X) = 7 is different from SAY (X) = 7

but

SAY(6) = 7 is the same as SAY (6) = 7

Now, try explaining that to the kind of audience that REXX is supposed
to be reaching.

Or perhaps do you mean that SAY is not a symbol and therefore does not
qualify? Then do you propose to make SAY = 7 or X = SAY + 1 illegal?

>IF(3)=4 THEN SAY HI is not of the form of an assignment, it is
>of the form of an IF instruction, and not any kind of assignment.

And what about IF(X) = Y THEN SAY LO? After all, how often do people
write code asking whether 3 is equal to 4? Is that a pseudofunction
because it is in the form symbol(var_list)?

(By the way, both of these would be legal assignments in today's REXX
if you replace IF(...) with FOO.)

And while we're on the topic of var_list, are you saying that

SAY(X,Y,Z) = 7

qualifies but

SAY(X,Y,"foo")

does not? And then, you could not say

SUBSTR(X,1,3) = "bar"

could you, by your definition? Also, you clearly do want to say
things like

PHONY_ARRAY(1) = "value of first element of phony array"

but you are preventing yourself from doing so, unless you make SAY, IF
et al. a special case (none dare say "reserved words").

- seb

Dave Gomberg

unread,
Aug 28, 1993, 4:14:51 PM8/28/93
to
On Sat, 28 Aug 1993 18:22:42 GMT Jack Hamilton said:
>Dave Gomberg <GOM...@UCSFVM.BITNET> wrote:
>
><deleted stuff>
>
>>Dave Gomberg, role model for those who don't ask much in their fantasy lives.
>>GOMBERG@UCSFVM Internet node UCSFVM.UCSF.EDU fax-> (415)731-7797
>
>Are you the same Dave Gomberg who has been mentioned on the radio show
>"West Coast Weekend", and did you recently have a letter published in
>"Verbatim: The Language Quarterly"?
>
>Perhaps (re your signature) you're busy enough not to need a fantasy life.

Yes to all the above. I am also the Dave Gomberg with the California Judicial
Council legal forms product. But I am not the Dave Gomberg kite flyer
extrordinaire, but I do have 18000 ft of kite line, for setting a world
altitude record. Now if I can only find a kite...

Ian Collier

unread,
Aug 29, 1993, 7:57:56 AM8/29/93
to
In article <1993082710...@MVS.draper.com>, SEB...@MVS.draper.com (Steve Bacher) wrote:

>More interesting would be what
>say value("7>6")
>returns. On TSO/REXX it generates an "Incorrect call to routine"
>error because 7>6 is not a valid variable name.

>(On the other hand, value(7>6) also ought to return an error,
>because 1 is not a valid symbol name.

>In Regina, value(7>6) returns 1, and value("7>6") returns 7>6.


>At least it's consistent, which is superior to what TSO/REXX does.

TSO/REXX is correct (I would say that, because REXX/imc does the same thing
:-) ).

"1" is a symbol (a constant one, but a symbol nevertheless). Given that
datatype("1","S") returns 1 and symbol("1") does not return "BAD", I would
expect value("1") not to give an error.

imc

Ian Collier

unread,
Aug 29, 1993, 8:04:39 AM8/29/93
to
In article <1993082719...@MVS.draper.com>, SEB...@MVS.draper.com (Steve Bacher) wrote:

>Not only that, but it should be perfectly OK to have

> say "Did you know that the value of 1e2 = 1 is..."
> say 1e2 = 1
> say "How about that?"

No problem with the above because say is obviously not a function call. It
isn't followed by a parenthesis.

>But by rejecting all those options, you have yet another
>unacceptable conclusion: say(6) = 7 is illegal.

I didn't imply that at all. I said that the only way to make that legal and
to give it a well-defined meaning was to reject the "pseudovariable" idea.
If I reject that, then the above is certainly legal and has a well-defined
effect. I didn't mean that all things which look like pseudovariables
should be classed as illegal!

>On the other hand, there are circumstances in which the space between
>an identifier and a left parenthesis is significant in REXX, and ANSI
>accepts this. So a bit of pedantry is unavoidable.

Possibly, and if you require a space between a keyword and a
left-parenthesis then you are only re-using a rule which is already in
existence. But then, I can always say "breakage!" :-)

imc

Roger Deschner

unread,
Aug 29, 1993, 11:49:34 AM8/29/93
to
I think you are all missing the point. Left-hand functions *ARE* useful,
intuitive, and general goodness. These details being discussed here are
merely picayune details. THIS IS A GOOD IDEA.

Rexx already has reserved words. The crypt has already been violated by X
and B, which really really really are reserved words already. I do not
like them, and I do not think there should be any more of them, but they
would not be a violation of some sacred purity.

THE BOOK (Cowlishaw) says about functions: "It is important to note that
the name of a function, FUNCTIONNAME, must be adjacent to the "(", with
*NO* blank in between, or the construct will not be recognized as a
function call. (A BLANK OPERATOR will be assumed at that point
instead.)"

I think this is pretty clear. If left-functions were to exist, then:

SAY(X) = 46 <-- call to the SAY function
SAY (X) = 46 <-- SAY command, will type something

There is a working example of left-functions in the SPSS language.
(Mainframe, Unix, Windows, but not PC, versions). It presents no
particular parsing problems, and some functions such as SUBSTR are
extremely useful on the left. I use them frequently when building SPSS
applications. They are totally intuitive to use. I want them in REXX.

And now for some more productive implementation details about
left-functions: How to support left-functions written in the REXX
language. I propose that it all be done through the variable RESULT.
With a left-function the result is the input, not the output. Upon entry,
a function which might be called as a left-function should do:

IF (SYMBOL('RESULT') = 'VAR') THEN DO
/* The code for being called as a left-function. This code uses the
value of variable RESULT as input. If the function was not intended
to be called as a left-function, produce error messages here. */
END
ELSE DO
/* The code for being called as an ordinary right-function. This
code sets RESULT via the RETURN statement. */
END

All the usual caveats about variable RESULT apply - but even more so.
The system can change its value on you, so if you value its value, save
it in some other variable before doing much of anything.

There are doubtless some ramifications of this which would need to be
worked out, but I present this as one way of implementing this which
would be consistent with what we already have.

Roger Deschner, University of Illinois at Chicago U52...@UICVM.UIC.EDU

Steve Bacher

unread,
Aug 30, 1993, 8:57:00 AM8/30/93
to
In article <93241.104...@uicvm.uic.edu>,
Roger Deschner <U52...@uicvm.uic.edu> writes:

>And now for some more productive implementation details about
>left-functions: How to support left-functions written in the REXX
>language. I propose that it all be done through the variable RESULT.
>With a left-function the result is the input, not the output. Upon entry,
>a function which might be called as a left-function should do:
>
> IF (SYMBOL('RESULT') = 'VAR') THEN DO
> /* The code for being called as a left-function. This code uses the
> value of variable RESULT as input. If the function was not intended
> to be called as a left-function, produce error messages here. */
> END
> ELSE DO
> /* The code for being called as an ordinary right-function. This
> code sets RESULT via the RETURN statement. */
> END

This presumes that the variable RESULT is unset on entry to a function.
Unless the function is a PROCEDURE, this isn't currently true, and is
therefore another change required to the language in order to make
this work - and an incompatible one at that.

I think a better model is to treat

LEFTFUNC(A,B,C) = D

as a call to

LEFTFUNC(A,B,C,D)

If I'm not mistaken, that's what Dave Gomberg describes in his
implementation. (Hey, I said "IF"...)

Also, this follows an established model: the Lisp array handling
macros in MacLisp (am I showing my age here?). The drawback is
that you are constrained to use functions that take a fixed number
of arguments.

Perhaps the best approach would be to wait for one of the Object
Oriented REXX implementations to come out with operator overloading
a la C++. Then we could overload the assignment operator, so that:

FOO~BAR = some(expression)

would behave meaningfully.

Dave Gomberg

unread,
Aug 30, 1993, 11:05:39 AM8/30/93
to
On Mon, 30 Aug 1993 12:57:00 GMT Steve Bacher said:
>I think a better model is to treat
>
> LEFTFUNC(A,B,C) = D
>
>as a call to
>
> LEFTFUNC(A,B,C,D)
>
Almost what I described. I suggest putting D first in the parameter
list because then it is in a known place and optional and omitted
arguments don't confuse things so much. Also because of the above,
the name must be different. Otherwise how would you differentiate
between SUBSTR(A,3)=1 and SUBSTR(A,3,1)?

Anders Christensen

unread,
Aug 30, 1993, 10:11:54 PM8/30/93
to
In article <930825.11...@MReXX-0.18> "F. Scott Ophof" <Op...@CS.UWINDSOR.CA> writes:

> I'm curious as to the reason for not "short-circuiting" the
> evaluation.

When an expression is short-circuited, the side-effects of the skipped
part of the expression are 'lost'. Sometimes you want that, and
sometimes you don't ...

The two most common situations where I've seen short-circuits in use
are:

1) In C, in order to protect the evaluation of an expression involving
pointers against a segmentation fault, something like:

if (ptr && ptr->next && ptr->next->value)
...

2) In Perl, as a sort of flow-control 'statement':

open FILE || die "Could not find file\n" ;

The first case is fairly irrelevant for a programming language like
Rexx, which doesn't have pointers. The second case is just an 'obscure'
(but very terse) form of an IF-statement, which will not be of much use
in Rexx (Rexx functions don't even return suitable values for such
short-circuit use).

Thus, the main advantage of short-circuits in Rexx is to optimize code
wrt speed. Although speed is a nice feature, it is hardly more
important than readability.

Another advantage of a proposed Rexx-specific use of short-circuit
expression evaluation is that you can write things like:

if symbol(foo)='VAR' & foo='bar' then
...

Where short-circuiting are used as a guard against NOVALUE triggering,
similar to the C example above. IMO, the best reason for not having
short-circuit evaluation is that simulating non-short-circuit in a
short-circuit language is worse than the opposite:

Simulating short-circuit in Rexx can make a few extra levels of
nesting, but it is very obvious what the meaning of the code is:

if a then
if b then
...

Simulating non-short-circuit in a short-circuit language often
uses temporary storage of one kind or another, e.g. temporary
variables, or forces evaluation by making local operations a
normal function

tmp_a = a
tmp_b = b
if a & b then
...

or even more elaborate methods (using C syntax):

if ( a ? b : ( b && 0 ))
...

Regards,
-anders <and...@pvv.unit.no>

Steve Bacher

unread,
Aug 31, 1993, 11:11:00 AM8/31/93
to
In article <ANDERS.93A...@lise1.lise.unit.no>,
and...@lise.unit.no (Anders Christensen) writes:

>The two most common situations where I've seen short-circuits in use
>are:
>
> 1) In C, in order to protect the evaluation of an expression involving
> pointers against a segmentation fault, something like:
>
> if (ptr && ptr->next && ptr->next->value)
> ...
>
> 2) In Perl, as a sort of flow-control 'statement':
>
> open FILE || die "Could not find file\n" ;
>
>The first case is fairly irrelevant for a programming language like
>Rexx, which doesn't have pointers. The second case is just an 'obscure'
>(but very terse) form of an IF-statement, which will not be of much use
>in Rexx (Rexx functions don't even return suitable values for such
>short-circuit use).

This strikes me as a classic strawperson argument: giving only two
examples, one with pointers and one with a Perl construct that REXXers
will be guaranteed to find arcane.

Saying that REXX doesn't have pointers doesn't deny the need for
short-circuiting a la (1). What if we had given this example:

(in C) if (x != 0 && y/x > foo) ...

Obviously the same need applies to REXX, and any programming language.

Same goes for

if (x == 1 || very_expensive_procedure(x) == 2) ...

These are not rare occurrences.

>Thus, the main advantage of short-circuits in Rexx is to optimize code
>wrt speed. Although speed is a nice feature, it is hardly more
>important than readability.

The non-short-circuit implementation that compels the nested-IF usage
sacrifices both speed and readability. (If REXX can have a partially
functional SELECT because people believe that it's both faster and more
readable than a series of IF's, then wouldn't the same people believe
that a single logical expression is also both faster and more readable
than the nested IF's?)

> Simulating short-circuit in Rexx can make a few extra levels of
> nesting, but it is very obvious what the meaning of the code is:
>
> if a then
> if b then
> ...
>
> Simulating non-short-circuit in a short-circuit language often
> uses temporary storage of one kind or another, e.g. temporary
> variables, or forces evaluation by making local operations a
> normal function
>
> tmp_a = a
> tmp_b = b
> if a & b then
> ...

Yes, but when does anyone specifically need non-short-circuiting? I
can't think of a case offhand, and if there is such a case, then it
clearly should be coded explicitly so that the reader can see the
sequential nature of the operations.

Reply all
Reply to author
Forward
0 new messages