Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Extract last word from a sentence

619 views
Skip to first unread message

Graham Hobbs

unread,
Nov 10, 2014, 1:56:15 PM11/10/14
to
I can do this but is ugly. Is there a simple way?
A variable contains a sentence with a variable number of words, each
word delimited by one or more spaces,
I need to extract the last word into a varibale call 'amount'.
Help appreciated please
Graham Hobbs

Robert AH Prins

unread,
Nov 10, 2014, 3:07:19 PM11/10/14
to
amount = word(sentence, words(sentence))

Robert
--
Robert AH Prins
robert(a)prino(d)org

Gerard_Schildberger

unread,
Nov 10, 2014, 3:22:24 PM11/10/14
to
Just in case the variable SENTENCE has
nothing but blanks, or is null, the following
code will avoid a SYNTAX error:


amount = word(sentence, max(1, words(sentence))

/*--or--*/

w=words(sentence)
amount = word(sentence, max(1, w))
____________________________________ Gerard Schildberger

Graham Hobbs

unread,
Nov 10, 2014, 3:50:59 PM11/10/14
to
Gentlemen,
Thanks kindly, what can I say .. don't get old:-)
Graham
---

Jeremy Nicoll - news posts

unread,
Nov 10, 2014, 4:20:28 PM11/10/14
to
Graham Hobbs <gho...@cdpwise.net> wrote:

>I can do this but is ugly. Is there a simple way?
>A variable contains a sentence with a variable number of words, each
>word delimited by one or more spaces,
>I need to extract the last word into a varibale call 'amount'.

Other posters have the conventional answer - which I should say is how I'd
do it... In normal language use, when the sentence is short, it probably
doesn't matter much how one tackles this. But if rather than a 'sentence'
one was processing an arbitrary list of words or tokens, it might be quicker
to do something like:

rev = reverse(longlist)
parse var rev rev .
lastone = reverse(rev)

Why? Because I'd expect the 'reverse()' function to iterate along a very
long string efficiently, and we're always being told that 'parse' is a very
efficient way to do things that you'd have thought could be done better by
purpose-made functions...

On the other hand, writing the parse part as: rev = word(rev,1)
means we could do: lastone = reverse(word(reverse(longlist),1))

It works fine with lists which only have one word in them or are empty.

The possible problem with: amount = word(sentence, words(sentence))
is the amount of work that rexx has to do first to count the number of words
in the sentence, and secondly to scan along the sentence again - in this
case right to the far end - counting words for a second time to find the
n'th one. If you had a million words... Of course, if the long list is
very long, making a second copy of it (using the reversing method) might
have memory use and time implications too.

--
Jeremy C B Nicoll - my opinions are my own.

Email sent to my from-address will be deleted. Instead, please reply
to newsre...@wingsandbeaks.org.uk replacing "aaa" by "284".

Arthur T.

unread,
Nov 10, 2014, 9:16:32 PM11/10/14
to
In Message-ID:<97226a5ll9dtkspoo...@4ax.com>,
I put together a quick-and-dirty time test of the methods so
far, plus two of my own. On my machine, method 4 is best or
next-best in time for all tested strings. Method 2, which was
guessed to be best for long, complicated strings, is instead very bad
for them (strings.6). Method 1 was best for the first 2 strings,
which may be close to what the OP had in mind.

As I said, it was quick and dirty. And watch out for line-wrap:

<code>
numloops = 5e5

strings.1 = 'This is a normal test.'
strings.2 = 'This has a blank at the end. '
strings.3 = '' /* will null break algorithm? */
strings.4 = ' ' /* will single blank break algorithm? */
strings.5 = 'OneWord'
strings.6 = copies(' a',1000) 'b' /* long string with *many*
words */
strings.0 = 6

methtot. = 0
methtot.0 = 4

do i = 1 for strings.0
say '1' format(method1(strings.i),4,4) amount
say '2' format(method2(strings.i),4,4) amount
say '3' format(method3(strings.i),4,4) amount
say '4' format(method4(strings.i),4,4) amount
end

do i = 1 for methtot.0
say i methtot.i
end

exit 0

METHOD1:
t0 = time("R")
str = arg(1)
do numloops
rev = reverse(str)
parse var rev rev .
amount = reverse(rev)
end
t1 = time("R")
methtot.1 = methtot.1 + t1
return t1

METHOD2:
str = arg(1)
t0 = time("R")
do numloops
amount = word(str, max(1, words(str)) )
end
t1 = time("R")
methtot.2 = methtot.2 + t1
return t1

METHOD3:
str = strip(arg(1))
t0 = time("R")
do numloops
lastblank = lastpos(' ', str)
amount = substr(str, lastblank+1)
end
t1 = time("R")
methtot.3 = methtot.3 + t1
return t1

METHOD4:
str = strip(arg(1))
t0 = time("R")
do numloops
lastblank = lastpos(' ', str) + 1
parse var str =(lastblank) amount
end
t1 = time("R")
methtot.4 = methtot.4 + t1
return t1
</code>

--
Arthur T. - ar23hur "at" pobox "dot" com

Jeremy Nicoll - news posts

unread,
Nov 10, 2014, 10:47:47 PM11/10/14
to
Arthur T. <art...@munged.invalid> wrote:

> I put together a quick-and-dirty time test of the methods so
>far, plus two of my own. On my machine, method 4 is best or
>next-best in time for all tested strings.


> Method 2, which was guessed to be best for long, complicated strings, is
> instead very bad for them (strings.6).

If you mean what I posted... I suggested that that method would be bad, not
best.

Your lastpos methods are an excellent idea!

I tried a slightly different main routine, but the same four METHOD1/2/3/4
routine defs, though I added a fifth, very like method3 except the '+1' is
in a different place, making that aspect more like method4... ie trying to
make just a substr/parse difference:

METHOD5:
str = strip(arg(1))
t0 = time("R")
do numloops
lastblank = lastpos(' ', str) + 1
amount = substr(str, lastblank)
end
t1 = time("R")
methtot.5 = methtot.5 + t1
return t1


My main code was based on yours:

numloops = 1e5

strings.1 = 'This is a normal test.'
strings.2 = 'This has a blank at the end. '
strings.3 = '' /* will null break algorithm? */
strings.4 = ' ' /* will single blank break algorithm? */
strings.5 = 'OneWord'
strings.6 = copies(' a',1000) 'b' /* 1001 words */
strings.7 = copies(' abc',10000) 'def' /* 10001 words */
strings.0 = 7

methtot. = 0
methtot.0 = 5

do i = 1 for strings.0
say "Numloops:" numloops
say "String" i "L="length(strings.i) "Beg:" left(strings.i,30)
say 'm1 rev rev' format(method1(strings.i),4,4) "'"amount"'"
say 'm2 word(words)' format(method2(strings.i),4,4) "'"amount"'"
say 'm3 last & substr+1' format(method3(strings.i),4,4) "'"amount"'"
say 'm4 last+1 & parse' format(method4(strings.i),4,4) "'"amount"'"
say 'm5 last+1 & substr' format(method5(strings.i),4,4) "'"amount"'"
say
end

say
say "Total times per method, numloops="numloops":"
say 'm1 rev rev' methtot.1
say 'm2 word(words)' methtot.2
say 'm3 last & substr+1' methtot.3
say 'm4 last+1 & parse' methtot.4
say 'm5 last+1 & substr' methtot.5
say

exit 0


and for example, on a pretty basic netbook, using oorexx 4.1.1, I got:

Numloops: 1E5
String 1 L=22 Beg: This is a normal test.
m1 rev rev 0.1870 'test.'
m2 word(words) 0.3750 'test.'
m3 last & substr+1 0.1880 'test.'
m4 last+1 & parse 0.1560 'test.'
m5 last+1 & substr 0.1410 'test.'

Numloops: 1E5
String 2 L=29 Beg: This has a blank at the end.
m1 rev rev 0.2660 'end.'
m2 word(words) 0.4530 'end.'
m3 last & substr+1 0.2190 'end.'
m4 last+1 & parse 0.2340 'end.'
m5 last+1 & substr 0.2820 'end.'

Numloops: 1E5
String 3 L=0 Beg:
m1 rev rev 0.1410 ''
m2 word(words) 0.5470 ''
m3 last & substr+1 0.1870 ''
m4 last+1 & parse 0.1720 ''
m5 last+1 & substr 0.1720 ''

Numloops: 1E5
String 4 L=1 Beg:
m1 rev rev 0.1720 ''
m2 word(words) 0.3280 ''
m3 last & substr+1 0.1560 ''
m4 last+1 & parse 0.1880 ''
m5 last+1 & substr 0.1720 ''

Numloops: 1E5
String 5 L=7 Beg: OneWord
m1 rev rev 0.2190 'OneWord'
m2 word(words) 0.4220 'OneWord'
m3 last & substr+1 0.2190 'OneWord'
m4 last+1 & parse 0.1870 'OneWord'
m5 last+1 & substr 0.2350 'OneWord'

Numloops: 1E5
String 6 L=2002 Beg: a a a a a a a a a a a a a a a
m1 rev rev 1.4060 'b'
m2 word(words) 7.7040 'b'
m3 last & substr+1 0.2340 'b'
m4 last+1 & parse 0.2340 'b'
m5 last+1 & substr 0.1880 'b'

Numloops: 1E5
String 7 L=40004 Beg: abc abc abc abc abc abc abc a
m1 rev rev 22.2810 'def'
m2 word(words) 70.6240 'def'
m3 last & substr+1 0.1880 'def'
m4 last+1 & parse 0.2340 'def'
m5 last+1 & substr 0.1870 'def'


Total times per method, numloops=1E5:
m1 rev rev 24.672000
m2 word(words) 80.453000
m3 last & substr+1 1.391000
m4 last+1 & parse 1.405000
m5 last+1 & substr 1.377000

Gerard_Schildberger

unread,
Nov 10, 2014, 11:24:32 PM11/10/14
to
On Monday, November 10, 2014 9:47:47 PM UTC-6, Jeremy Nicoll - news posts wrote:
Since method 3, 4, and 5 require that trailing blanks be removed
in order for LASTPOS (for a blank) to work, the STRIP (trailing
blanks) should be measured as part of the DO loop.

Method 1 and 2 don't require blanks to be striped, so there even
isn't a need to include the REXX statements in their test, even
though that part of the code isn't within the timings.

Methods 3 --> 5 would be faster if LASTBLANK wasn't set, but the
value was just used directly. It does make the code a wee bit
harder to read, but comments always help.
_______________________________________ Gerard Schildberger

Arthur T.

unread,
Nov 11, 2014, 12:38:37 AM11/11/14
to
In
Message-ID:<b9b9a837-2285-4b7e...@googlegroups.com>,
Gerard_Schildberger <gera...@rrt.net> wrote:

>Since method 3, 4, and 5 require that trailing blanks be removed
>in order for LASTPOS (for a blank) to work, the STRIP (trailing
>blanks) should be measured as part of the DO loop.

Good point. The methods require only the trailing blank to be
stripped, but I know from previous experience that it's faster to
strip both.

The PARSE version (method 4) could probably get by without the
strip() if a period were appended to the template. Obviously,
testing would be required.

<snip>

>Methods 3 --> 5 would be faster if LASTBLANK wasn't set, but the
>value was just used directly. It does make the code a wee bit
>harder to read, but comments always help.

Another good point. But I've put in my 2 cents, and I'll
probably bow out of further tweaking.

LesK

unread,
Nov 11, 2014, 1:15:31 AM11/11/14
to
I notice that the original question implies that the last word is a
number ('amount'), yet none of the solutions proffered test for trailing
punctuation and no one asked if the implication was true.

Is it, in fact, a number? Perhaps with a leading currency symbol?


--

Les (Change Arabic to Roman to email me)

Swifty

unread,
Nov 11, 2014, 1:59:25 AM11/11/14
to
On 10/11/2014 20:50, Graham Hobbs wrote:
> Thanks kindly, what can I say .. don't get old:-)

If you are using any version or derivative of Object rexx, then you
could create a new function in a subroutine library, where it will
always be available:

1. Edit a subroutine library, I call mine Subroutines.Rex
2. Add the following code (my version):
::Routine xword public
-- Extended word(); adds -ve word index. -1 = last word
Parse arg string,N,char
If \datatype(N,'W') | length(char) > 1 then raise syntax 40
If char <> '' then string = translate(string,char' ',' 'char)
If N < 0 then N = words(string) + N + 1
If N <= 0 then return ''
Word = word(string,n)
If char <> '' then word = translate(word,char' ',' 'char)
Return word
3. Add the following line at the bottom of your program:
::Requires 'Subroutines.Rex'
4. Change your code to do this:
Last_Word = xword(string,-1)

My code will also parse off the last word from a string with arbitrary
delimiters (instead of blanks), e.g.
Say xword('One apple, Two pears, Ripe Bananae',-1,",")
... says "Ripe Bananae" (British marketplace call)

My subroutine library is stuffed full of little routines like this,
implementing all the function that I always wished REXX had as standard.
Nothing gives me more pleasure that being able to delete one of my
routines when the product implements one of my routines. I say "mine"
guiltily; many of the routines were given to me here.



--
Steve Swift
http://www.swiftys.org.uk/

Swifty

unread,
Nov 11, 2014, 2:04:07 AM11/11/14
to
On 11/11/2014 06:59, Swifty wrote:
> 3. Add the following line at the bottom of your program:
> ::Requires 'Subroutines.Rex'

I forgot to mention:

If you're on a system whose filenames are not case-sensitive (e.g.
Windows) then you can use:

::Requires Subroutines.rex /* No quotes, case-insensitive */

… as long as you don't have a stem variable "subroutines." :-)

Gerard_Schildberger

unread,
Nov 11, 2014, 5:47:23 PM11/11/14
to
Yes, I re-read the original post, and it (kinda) implies that the last word is sorta a number in that it refers to "it" as an amount, or, ... at least, that's
what the variable name is ... er, named. It could've been called HowMuch.

However, who hasn't been burned before with such requirements/definitions
and/or assumptions and/or guesstimation-ing? (Or maybe, wishful thinking?)

The amount could be English words such as forty-four, a dozen, 100!, 750Gi,
googol, Skew's or Graham's (number), quattuorquinquagintanongentillion, a
number with imbedded commas such as 60,000,000 or an imbedded decimal
point AND a period such as 450.00.

Not to mention: 11.2e+99, 11.2d+99, 11.2q+99 and others of such ilk.

And, ... holy doughnuts Batman! 4+5.5j ... and quaternions.

Oh! Lions and tigers and bears! Oh my!

Or it could be an ambiguous amount such as "not much", lots, some, few,
many, ample, gihugeic, ginormous, hunka-hunka, or Yikes!

The "number" (last "word"/symbol) may or may not have ending punctuation
and/or leading currency symbols. Yadda, yadda, yadda.

[Re-read Dorothy's quote.]
__________________________________________________ Gerard Schildberger



Jeremy Nicoll - news posts

unread,
Nov 11, 2014, 6:07:06 PM11/11/14
to
Gerard_Schildberger <gera...@rrt.net> wrote:

> Yes, I re-read the original post, and it (kinda) implies that the last
> word is sorta a number in that it refers to "it" as an amount, or, ... at
> least, that's what the variable name is ... er, named. It could've been
> called HowMuch.
>
> However, who hasn't been burned before with such requirements/definitions
> and/or assumptions and/or guesstimation-ing? (Or maybe, wishful
> thinking?)
>
> The amount could be English words ...

Goodness Gracious Me! I don't think I've ever seen a post from you with so
many words and so litte (well, no) code! Did you get a special offer on
the contents of an online dictionary? ;-)

--
Jeremy C B Nicoll - my opinions are my own.

Gerard_Schildberger

unread,
Nov 11, 2014, 6:28:42 PM11/11/14
to
On Tuesday, November 11, 2014 5:07:06 PM UTC-6, Jeremy Nicoll - news posts wrote:
> Gerard_Schildberger wrote:
> > Yes, I re-read the original post, and it (kinda) implies that the last
> > word is sorta a number in that it refers to "it" as an amount, or, ... at
> > least, that's what the variable name is ... er, named. It could've been
> > called HowMuch.
> >
> > However, who hasn't been burned before with such requirements/definitions
> > and/or assumptions and/or guesstimation-ing? (Or maybe, wishful
> > thinking?)
> >
> > The amount could be English words ...
> Goodness Gracious Me! I don't think I've ever seen a post from you with so
> many words and so litte (well, no) code! Did you get a special offer on
> the contents of an online dictionary? ;-)
> --
> Jeremy C B Nicoll - my opinions are my own.

Every once in a while, depending on my diet, I/ve been known to get
diarrhea of the fingers. Not as bad as the other kind, but still ...
_________________________________________ Gerard Schildberger


Blue Bullet

unread,
Nov 12, 2014, 1:02:09 PM11/12/14
to
That's the Gerard I know and remember with fondness. Let him free associate. It cleans him out. At least he did not start in with the Jacobians, Hessians,
and annihilators...

Back on topic. How are you all deciding which method is best? I found this
text file from some testing I did on linux 4 years ago comparing use of the stack vs using return to pass data between rexx routines
:

Command being timed: "test1.rexx 10000 n"
User time (seconds): 0.45
System time (seconds): 0.18
Percent of CPU this job got: 91%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.69
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 5792
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 10423
Voluntary context switches: 1
Involuntary context switches: 80
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
Command being timed: "test1.rexx 10000 n"
User time (seconds): 0.40
System time (seconds): 0.21
Percent of CPU this job got: 100%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.62
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 5808
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 10423
Voluntary context switches: 1
Involuntary context switches: 96
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
Command being timed: "test1.rexx 10000 n"
User time (seconds): 0.42
System time (seconds): 0.18
Percent of CPU this job got: 99%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.62
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 5824
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 10424
Voluntary context switches: 1
Involuntary context switches: 82
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0


What measure should use to select the superior method?

LesK

unread,
Nov 12, 2014, 5:06:07 PM11/12/14
to
On 11/12/2014 1:02 PM, Blue Bullet wrote:

> Back on topic. How are you all deciding which method is best? I found this
> text file from some testing I did on linux 4 years ago comparing use of the stack vs using return to pass data between rexx routines
> :
(snip)
> What measure should use to select the superior method?
>
Wrong question! Should be: Why does running the same test 3 times yield
different measurements?

Jeremy Nicoll - news posts

unread,
Nov 12, 2014, 8:31:50 PM11/12/14
to
LesK <5mr...@tampabay.rr.com> wrote:

>On 11/12/2014 1:02 PM, Blue Bullet wrote:

>> What measure should use to select the superior method?
>>
> Wrong question! Should be: Why does running the same test 3 times yield
> different measurements?

Probably those three tests didn't run in the same machine environment - by
which I mean a machine which has had exactly the same work run on it
beforehand, has the exact same other work running at the same time, etc.

Activities of other tasks in the system, memory use & fragmentation,
overheads of eg paging... all sorts of things make a difference especially
if all one is measuring is elapsed time.

On the other hand, real use of any program is going to occur with the same
constraints so it's useful to see how much variation the apparently same
amount of work will cause in whatever you choose to measure.

--
Jeremy C B Nicoll - my opinions are my own.

Graham Hobbs

unread,
Nov 12, 2014, 9:40:48 PM11/12/14
to
On Tue, 11 Nov 2014 01:15:30 -0500, LesK <5mr...@tampabay.rr.com>
wrote:
If it's a number I want it else not interested.
I downloaded a municipal accounts PDF and used omnipage to convert it
to text.
Eyeballing showed that every record ending in a number was an invoice
line, last word being the amount. Am now using:

amount1 = word(b01, max(1,words(b01)))
typdt = datatype(amount1)
if typdt = 'NUM' then ..

Many thanks for the interesting discussion
Graham Hobbs

Blue Bullet

unread,
Nov 13, 2014, 11:40:45 AM11/13/14
to
Les,
My apologies for axing the wrong question. I hate it when I do that. ;->

A.D. Fundum

unread,
Nov 13, 2014, 3:58:40 PM11/13/14
to
> If you are using any version or derivative of Object rexx,
> then you could create a new function in a subroutine
> library, where it will always be available:

The off-topic magic of Object Rexx. I think any version of Rexx
supports external subroutines, which will always be available, without
the overhead of objects to use your classic Rexx solution with its own
overhead.


--

Jeremy Nicoll - news posts

unread,
Nov 13, 2014, 5:06:53 PM11/13/14
to
"A.D. Fundum" <what...@neverm.ind> wrote:

> > If you are using any version or derivative of Object rexx,
> > then you could create a new function in a subroutine
> > library, where it will always be available:
>
>The off-topic magic of Object Rexx.

It's not off-topic here.

> I think any version of Rexx supports external subroutines, which will
> always be available

Yes, but rather fewer support the idea of having all those routines that
you're likely to need contained in one file and this loaded all together,
also before execution starts, rather than as & when they are needed.

(I know of environments where one can preload execs, eg in IBM's NetView one
can 'LOADCL' clists (which can be rexx execs) so they are available to any
person or task running in that NetView address space...)

> without the overhead of objects to use your classic Rexx solution with its
> own overhead.

I use ooREXX all the time here, but I hardly ever use any of its oo aspects.
Almost all my code is classic in style. Features like this ability to load
all those common routines at once, though, are very useful. Or would be if
I could only establish a set of common routines... I've got too many execs
with subtlely different almost-the-same-as-everywhere-else routines in them.

Michel Castelein

unread,
Nov 14, 2014, 5:35:58 AM11/14/14
to
amount = WORD(variable,WORDS(variable))

Michel Castelein
z/OS instructor

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

Michel Castelein

unread,
Nov 14, 2014, 5:36:01 AM11/14/14
to
Just FYI: I'm 60.

Andreas Schnellbacher

unread,
Nov 14, 2014, 12:17:01 PM11/14/14
to
Jeremy Nicoll wrote:

> I use ooREXX all the time here, but I hardly ever use any of its oo
> aspects. Almost all my code is classic in style. Features like this
> ability to load all those common routines at once, though, are very
> useful.

Sure. The reason for the OP is most likely that on OS/2, the OREXX
version is near to unusable, due to a severe memory bug.

--
Andreas Schnellbacher

Swifty

unread,
Nov 15, 2014, 2:10:59 AM11/15/14
to
On 13/11/2014 20:46, A.D. Fundum wrote:
> I think any version of Rexx
> supports external subroutines, which will always be available

Indeed, but at a performance penalty. I purposely avoided explaining
this advantage of the ::Requires directive because too much detail can
be off-putting to someone considering a small change in technology.

This certainly applied to me, and I've only made the feeblest of
ventures into the object nature of oorexx. That doesn't stop me taking
advantage of features of Object Rexx in my Classic Rexx coding style.

Try a benchmark. Write your best effort at a lastword() function, as an
external function, then us it in a loop to find the last word in
1,000,000 different sentences.

Then move it to a ::Routine in an external library and run the benchmark
again. It will be orders of magnitude faster, for the simple reason that
Classic Rexx fetches external routines every time they are called. The
Object Rexx library is read once, and parsed once for the entire
lifetime of your benchmark program.

I migrated to Object Rexx for this reason alone. I had a process that
was using REXX to build dynamic webpages. If a webpage doesn't respond
in a second, most people click away from it. I had to reduce the elapsed
time of my code from 3 seconds. Object REXX got it down to 0.1 seconds,
with no change in my executable code. And no objects in sight!

LesK

unread,
Nov 15, 2014, 3:17:57 PM11/15/14
to
On 11/15/2014 2:10 AM, Swifty wrote:
> On 13/11/2014 20:46, A.D. Fundum wrote:
>> I think any version of Rexx
>> supports external subroutines, which will always be available
>
> Indeed, but at a performance penalty.

(snip)

> Then move it to a ::Routine in an external library and run the benchmark
> again. It will be orders of magnitude faster, for the simple reason that
> Classic Rexx fetches external routines every time they are called.


(snip)
--
The re-fetching can be bypassed on the VM mainframe by using EXECLOAD to
put it in storage and leave it there.

Gerard_Schildberger

unread,
Nov 15, 2014, 5:25:37 PM11/15/14
to
Indeed. Using REXX under CMS had that feature, and made it extremely
efficient running REXX programs. I modified my PROFILE EXEC (for CMS)
to EXECLOAD several of my most common REXX programs, as well as my
XEDIT PROFILE (a REXX program). _______________ Gerard Schildberger

LesK

unread,
Nov 16, 2014, 12:30:20 AM11/16/14
to
The neatest trick with EXECLOAD is that you can load _any_ arbitrary
filename/filetype _as_ the needed filename/filetype. This is great for
testing, proof of concept, performance comparisons or even disguising
code on disk.

--

Shmuel Metz

unread,
Nov 16, 2014, 11:41:08 AM11/16/14
to
In <m49cp7$69f$1...@speranza.aioe.org>, on 11/16/2014
at 12:30 AM, LesK <5mr...@tampabay.rr.com> said:

>The neatest trick with EXECLOAD is that you can load _any_
>arbitrary filename/filetype _as_ the needed filename/filetype.

How does that differ from RexxAddMacro in ObjectRexx?

--
Shmuel (Seymour J.) Metz, SysProg and JOAT <http://patriot.net/~shmuel>

Unsolicited bulk E-mail subject to legal action. I reserve the
right to publicly post or ridicule any abusive E-mail. Reply to
domain Patriot dot net user shmuel+news to contact me. Do not
reply to spam...@library.lspace.org

Gerard_Schildberger

unread,
Nov 16, 2014, 2:12:20 PM11/16/14
to
On Sunday, November 16, 2014 10:41:08 AM UTC-6, Seymour J. Shmuel Metz wrote:
> on 11/16/2014 at 12:30 AM, LesK said:
>
> >The neatest trick with EXECLOAD is that you can load _any_
> >arbitrary filename/filetype _as_ the needed filename/filetype.
>
> How does that differ from RexxAddMacro in ObjectRexx?
>
> --
> Shmuel (Seymour J.) Metz, SysProg and JOAT

(CMS') EXECLOAD persistence endures the length of the time the user
stays logged on (and stays in the CMS environment). Even after the
REXX program finishes, the EXECLOADed program stays in virtual memory
(unless EXECDROPed), or until some (user) IPL is performed. So a
subsequent execution of any REXX program could use what has been
EXECLOADed previously by some other (REXX or whatever) program or
CMS command. Also, the use of EXECLOAD and EXECDROP isn't dependent
on ooRexx. _____________________________________ Gerard Schildberger

Andreas Schnellbacher

unread,
Nov 16, 2014, 4:05:58 PM11/16/14
to
Shmuel (Seymour J.) Metz wrote:

> How does that differ from RexxAddMacro in ObjectRexx?

Not an answer, but with respect to the comment of A. D. Fundum: On
OS/2 we use the REXXUTIL.DLL from OREXX. Most likely due to
compatibility, the macro space functions are not widely used. We have:

SysLoadRexxMacroSpace
SysSaveRexxMacroSpace
SysClearRexxMacroSpace
SysAddRexxMacro
SysReorderRexxMacro
SysDropRexxMacro
SysQueryRexxMacro

--
Andreas Schnellbacher

Jeremy Nicoll - news posts

unread,
Nov 16, 2014, 6:46:18 PM11/16/14
to
Gerard_Schildberger <gera...@rrt.net> wrote:

>(CMS') EXECLOAD persistence endures the length of the time the user
>stays logged on (and stays in the CMS environment).

I had the idea that this is possible, up to a point, in z/OS too, and had a
quick google. Yes, it's possible to use VLF for this (if your z/OS sysprog
is willing to set it up) though it's only useful for main-line execs (ie no
use for external functions). I have no idea whether the performance
improvement is worth the hassle. See the last section at:

<url:http://www-01.ibm.com/support/knowledgecenter/SSLTBW_1.13.0/com.ibm.zos.r13.ikjb400/part6.htm%23part6>

A.D. Fundum

unread,
Nov 16, 2014, 7:17:35 PM11/16/14
to
FWIW. Good:

> typdt = datatype(amount1)
> if typdt = 'NUM' then ..

Better coding style, avoiding assigning a return value to a variable
and comparing this variable to another value:

if datatype(amount1)='NUM' then ...

Best, if you are inside a file-processing loop:

if datatype(amount1,'N')=1 then ...

(or datatype(amount,'NUM')=1 then ...)


--

Gerard_Schildberger

unread,
Nov 16, 2014, 8:57:25 PM11/16/14
to
Better still:

if datatype(amount1,'N') then ...

--- [since the result of this type invoke of
the DATATYPE BIF is either 1 or 0]
________________________ Gerard Schildberger

Shmuel Metz

unread,
Nov 17, 2014, 11:37:07 AM11/17/14
to
In <ccshtk...@mid.uni-berlin.de>, on 11/16/2014
at 10:05 PM, Andreas Schnellbacher <as...@despammed.com> said:

>Not an answer, but with respect to the comment of A. D. Fundum: On
>OS/2 we use the REXXUTIL.DLL from OREXX.

That's for compiled code. RexxAddMacro is for Rexx source code.

LesK

unread,
Nov 17, 2014, 10:36:17 PM11/17/14
to
On 11/16/2014 7:55 PM, Shmuel (Seymour J.) Metz wrote:
> In <ccshtk...@mid.uni-berlin.de>, on 11/16/2014
> at 10:05 PM, Andreas Schnellbacher <as...@despammed.com> said:
>
>> Not an answer, but with respect to the comment of A. D. Fundum: On
>> OS/2 we use the REXXUTIL.DLL from OREXX.
>
> That's for compiled code. RexxAddMacro is for Rexx source code.
>
Huh? The only Rexx compiler is for the mainframe, not OS/2.

Shmuel Metz

unread,
Nov 18, 2014, 12:07:45 AM11/18/14
to
In <m4eerb$2ma$1...@speranza.aioe.org>, on 11/17/2014
at 10:36 PM, LesK <5mr...@tampabay.rr.com> said:

>On 11/16/2014 7:55 PM, Shmuel (Seymour J.) Metz wrote:
>> In <ccshtk...@mid.uni-berlin.de>, on 11/16/2014
>> at 10:05 PM, Andreas Schnellbacher <as...@despammed.com> said:
>>
>>> Not an answer, but with respect to the comment of A. D. Fundum: On
>>> OS/2 we use the REXXUTIL.DLL from OREXX.
>>
>> That's for compiled code. RexxAddMacro is for Rexx source code.
>>
>Huh? The only Rexx compiler is for the mainframe, not OS/2.

How is that relevant? OS/2 has compilers for, e.g., C. My statement
was *not* "That's for compiled Rexx code."
0 new messages