X-Array Code Not Working

I’d like to use a dynamic array in my code and found some documentation about X-Arrays. My version of Natural is 4.2.6, so I believe this should work. When I run my program, it doesn’t blow up. However, it doesn’t show me any output for my dynamic array. Here’s my code (with file and key names changed to generic names):

In my local data area, I have my array defined as:

01 #ITEM-ARRAY(A8/1:) / DYNAMIC ARRAY W/UNLIMITED UPPER BOUND


READ WORK FILE 4 #WKF04
  ADD 1 TO #WF4-READ
  MOVE #X TO #KEY-X
  MOVE #ITEM TO #KEY-ITEM
  FD-IT. FIND [FILE] WITH [KEY] = #KEY
    IF *NUMBER(FD-IT.) = 0
      ADD 1 TO #NOFOUND
      DISPLAY '=' #NOFOUND                                           /* JUST TO SEE IF MY CODE GETS THIS FAR
      EXPAND ARRAY #ITEM-ARRAY TO (1:#NOFOUND)      /*EXPAND X-ARRAY
      MOVE #ITEM TO #ITEM-ARRAY(#NOFOUND)
      ESCAPE BOTTOM
    END-IF
    ADD 1 TO #FOUND
    .... continue processing for found records
  END-FIND
END-WORK
*
WRITE 'RESULTS OF PROGRAM:' /
  #WF4-READ (EM=ZZZ,ZZZ,ZZZ,ZZ9) 'WORK FILE 4 RECS READ' /
  #FOUND(EM=ZZZ,ZZZ,ZZZ,ZZ9) 'RECS FOUND'
  IF #NOFOUND > 0
    WRITE #NOFOUND(EM=ZZZ,ZZZ,ZZZ,ZZ9) 'RECS NOT FOUND'
    FOR #I = 1 TO #NOFOUND
      WRITE / 21T #ITEM-ARRAY(#I)
    END-FOR
  END-IF
END

Here is my output:

PAGE 1
#NOFOUND

RESULTS OF PROGRAM:
134 WORK FILE 4 RECS READ
0 RECS FOUND

I’ve manipulated my work file data so that all 134 records should not be found. Any ideas of where I may be going wrong?

If your FIND at line 5 does not find anything, it will not enter the loop, so the IF *NUMBER at line 6 never gets executed. You need to move the IF *NUMBER below the find loop.

Thanks, Jerome!

You might also want to take a look at the IF NO RECORDS FOUND clause of the FIND statement.

Thanks for your response, Steve. I was told to steer clear of the IF NO RECORDS FOUND clause because it initiates another processing loop whereas the IF *NUMBER = 0 avoids that. Is that not true or is the difference between the two negligible?

No, it doesn’t really initiate a processing loop, what the documentation says here is

Thank you, Wolfgang. This shows me that I need to do my homework and read the Software AG documentation to verify any future “helpful programming tips” that I read out there online.

Just a few other notes: the EXPAND (or RESIZE) command is a relatively expensive one to use - typical expansion requires allocating new space, copying old values in and freeing up old space.

Whenever you know what size your array will be, use that rather than incrementing the array size one element at a time. In some cases, *NUMBER contains the number of records that will be returned, so you can use an AT START OF DATA or IF *COUNTER = 1 and EXPAND the array to hold *NUMBER occurrences. If your loop will contain conditional logic such that your array will likely end up with fewer than *NUMBER occurrences filled in, use the REDUCE statement outside the loop to reduce the dynamic array down to its actual occurrences. In your example, you might start with an estimate of how many items will be read and match your criterion for adding to the array, and if you fill that up, increase the array by some factor (25%? 50%? 100 occurrences? 1000 occurrences? know your data!) with an EXPAND before adding the next row of data rather than doing an EXPAND on every iteration through the loop.

Other application scenarios may have other logic needed, but the goal is to minimize the number of times you have to execute the EXPAND statement to help minimize CPU usage.

I think the problem is that if there are no hits to the FIND statements, then you will never enter the find-loop, and thus never test the *number condition.
The simple trick is to replace the test with a
IF NO [RECORDS] [FOUND]
…statement
END-NOREC
(see:http://techcommunity.softwareag.com/ecosystem/documentation/natural/nat822mf/sm/find.htm#IF_NO_RECORDS_FOUND-clause)

In this way you will force the program execution into the source part where you do the x-array magic :wink:

Finn

Thanks for the good suggestion, Douglas. If I understand you correctly, I could initialize my upper bound of the array at 100, and then if that upper bound is reached, increase it by a certain percentage or number. So my code would then look like this:


READ WORK FILE 4 #WKF04
  ADD 1 TO #WF4-READ  
  MOVE #X TO #KEY-X  
  MOVE #ITEM TO #KEY-ITEM  
  FD-IT. FIND [FILE] WITH [KEY] = #KEY  
    IF NO RECORDS FOUND
      ADD 1 TO #NOFOUND  
      IF #NOFOUND = 1
        EXPAND ARRAY #ITEM-ARRAY TO (1:#U-BOUND)      /*INITIAL EXPANSION OF X-ARRAY (INITIALIZED AT 100 IN LDA)
      END-IF
      MOVE #ITEM TO #ITEM-ARRAY(#NOFOUND)  
      IF #NOFOUND = #U-BOUND
        COMPUTE #U-BOUND = #U-BOUND + 25
        EXPAND ARRAY #ITEM-ARRAY TO (1:#U-BOUND)      /*INCREASE UPPER BOUND OF X-ARRAY
      END-IF
      ESCAPE BOTTOM  
    END-NOREC  
    ADD 1 TO #FOUND  
    .... continue processing for found records  
  END-FIND  
END-WORK