Tuesday, November 17, 2020

Range test added to RPG

%range bif added to rpg

The latest Technology Refreshes, IBM i 7.4 TR3 and 7.3 TR9, have added something I have wanted for a long time added to the RPG programming language, the ability to test if a value is within a range. This has been achieved by the introduction of a new Built in Function, %RANGE, and a new operation code, IN.

The syntax is very similar to the Range test I use in SQL:

if <value or variable> in %range(<minimum value or variable> :
                                 <maximum value or variable>) ;

Let me get on with some simple examples. First with a date:

01  **free

02  dcl-s InRange ind ;

06  if %date() in %range(d'2020-11-01' : d'2020-11-30') ;
07    InRange = *on ;
08  endif ;

09  dsply ('Date = ' + %char(InRange)) ;

Line 1: If I am doing things in RPG why would I want to do it in an old version of our favorite programming language?

Line 2: The only purpose for this variable is to know if the Range test was successful or not.

Lines 3 – 5: Will be shown later.

Line 6: Testing the current date, using built in function %DATE() with no parameter, if it is in this month, November 1 – 30, and this year.

Line 7: If the test was successful, today is in this month, then the indicator InRange is turned on.

Line 9: I am using the Display operation code, DSPLY, to see the value of the indicator and whether my test was successful. Which it was:

DSPLY  Date = 1

Now with numbers...

10  if 7 in %range(1 : 10) ;
11    InRange = *on ;
12  else ;
13    InRange = *off ;
14  endif ;

15  dsply ('Number = ' + %char(InRange)) ;

Line 10: Is the number seven in the range of numbers between one and ten?

Line 11: Of course it is.

Line 15: So my indicator will display:

DSPLY  Number = 1

Next character values...

16  if 'ABCD' in %range('A' : 'B') ;
17    InRange = *on ;
18  else ;
19    InRange = *off ;
20  endif ;

21  dsply ('Char 1 = ' + %char(InRange)) ;

Line 16: "ABCD" is between the values of "A" and "B".

Line 21: Therefore, the indicator is on.

DSPLY  Char 1 = 1

What happens if I reverse the values in the Range BiF, and put the higher value in the first parameter and the lower in the second.

22  if 'ABCD' in %range('B' : 'A') ;
23    InRange = *on ;
24  else ;
25    InRange = *off ;
26 endif ;

27  dsply ('Char 2 = ' + %char(InRange)) ;

Line 22: No value can satisfy this range criteria.

Line 27: And the indicator is off.

DSPLY  Char 2 = 0

I have used values above, not variables. Here are a couple examples using variables:

03  dcl-s MinValue char(10) inz('Houston') ;
04  dcl-s MaxValue like(MinValue) inz('Yznaga') ;
05  dcl-s TestValue like(MinValue) inz('Dallas') ;

28  if TestValue in %range(MinValue : MaxValue) ;
29    InRange = *on ;
30  else ;
31    InRange = *off ;
32  endif ;

33  dsply ('City 1 = ' + %char(InRange)) ;

Lines 3 – 5: Here are those missing lines I mentioned before, that define the three variables I will be using.

Line 28: Testing if the city Dallas is within the range of city names of Houston to Yznaga.

Line 33: And it is not so the indicator is off.

DSPLY  City 1 = 0

Let me try that again with another city name.

34  TestValue = 'Round Rock' ;

35  if TestValue in %range(MinValue : MaxValue) ;
36    InRange = *on ;
37  else ;
38    InRange = *off ;
39  endif ;

40  dsply ('City 2 = ' + %char(InRange)) ;

Line 35: The city of Round Rock is in the range.

Line 40: And the indicator shows that.

DSPLY  City 2 = 1

These two are a great addition and I can see me using them a lot. Now what about a %VALUES BiF?


You can learn more about the %RANGE Built in Function from the IBM website here.


This article was written for IBM i 7.4 TR3 and 7.3 TR9.


  1. Happy to hear about this. Thanks. Also, can tell you're a Texan now!

  2. if 'ABCD' in %range('A' : 'B') ;

    How is this true? Is only the first byte being tested, because the range values are 1 byte?

    1. All code I show is tested before I include it in a post. I have to admit I could not find a reference in the documentation stating if it only checks the first byte or whether is checks the entire string.

    2. Documentation says those statements are equivalent
      IF x IN %RANGE(y1 : y2);
      IF x >= y1 AND x <= y2;

      I think
      if 'ABCD' in %range('A' : 'B') ; is equivalent to
      if 'ABCD' >= 'A' and 'ABCD' <= 'B'
      and what you have in mind is
      if %subst('ABCD':1:1) in %range('A' : 'B') ;

  3. If you compare 'ABCD' with 'A', 'ABCD' is greater then 'A' but if you compare 'ABCD' with 'B, 'ABCD' is lower then 'A' so the result of %range is correct.

    Is like you made

    IF 'ABCD' IN %RANGE('A ' : 'B ');

  4. Try this

    IF 'ABCD' IN %RANGE('A' : 'A'); This is false so you can understand that is not the first byte tested

  5. can you use it to set an indicator field directly:

    TestFldValidInd = testFld in %range(minFld : maxFld);

  6. I am thinking for screen validation routine, flagging all of the errors and redisplaying

  7. Do you prefer the "if" wrapper or write the check in one line like:

    InRange = ( TestValue in %range(MinValue : MaxValue)) ;

    1. if the only logic I am going to do is set an indicator based on the results of the if, I prefer to set it directly with comments as to what it is doing.

  8. Simon, what do you mean by a %VALUES bif?

    1. It is a long held wish of mine where I could have a BiF that I could then compare a variable to a list of values.
      But as you know that is now possible and will be revealed tomorrow.

    2. You already have it Simon - it os called %LIST and is in the same set of PTFs.

    3. I was using this as a "teaser" for today's post, which gives plenty examples of using %LIST.

  9. If Answer in %Values(‘Y’: ‘N’); would be nice, where the values can be any number of parameters.

  10. Simon, thanks for sharing. Great read with great example. It’s been a long time coming. The %range BIF (build-in- function) will be very useful with the new types of data being added to the box. Thanks.

  11. Y cómo se hace la validación contraria?, por ejemplo if not (x> 0 and x<5)

    1. IN %RANGE returns an indicator value. If I wanted to check if something is not within the range I could do the following:

      dcl-s InRange ind ;

      InRange = DTEBIRTH in %range(d'1910-01-01' : d'1920-01-01') ;
      if not(InRange) ;
      dsply ('Not in range ' + %char(DTEBIRTH)) ;
      endif ;

      InRange will be "off" if the value is not in the range.


To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.