3

I am trying to make a procedure that will take an array and return a count of the used elements (why is this not a BIF??). I am struggling to find a way to pass an array of unknown size to my procedure.

Something like...

P count         B
D count         PI              3  0 
D  array                         *
D  size                        10  0
D  elems                        3  0
 *
D ct            S               3  0
 /free
  // find the first blank or zero element and return 
 /end-free
P count         E

Obviously I am new to this, so I have a couple of questions:

  1. Is there any way around passing the size and max elements as parameters (or maybe a way of passing a sort of header packet with details about the data)?
  2. Is there any way of determining what type the data is? (so I know whether to look for *ZEROS or *BLANKS)
  3. Am I missing some other, better approach to this problem?

I know I could keep a separate counter variable that gets incremented whenever I set an element in the array, but I would really like to find a better solution... thank you for reading.

Sarah Kemp
  • 2,670
  • 3
  • 21
  • 29

2 Answers2

7

I've been programming in RPG for... well, for a very long time. It's marvelous to see a new RPG programmer and it's doubly marvelous to see modern coding concepts used from the get-go.

RPG started life with fixed-size everything. Fixed size strings, fixed size numbers and fixed-size arrays. Being a strongly typed language based on punched cards, this all made sense. Of course, modern computing requirements tend to want varying-sized strings, numbers and arrays. RPG is still strongly-typed, so a given variable can only ever be a string or a number; it can never switch types. Which also means that the compiler hasn't got a means to determine the variable type at run time - the variable type is immutable and the programmer and compiler both know what that type is. Oh well.

As for your varying length array, there's some hope for that. Mihael Schmidt has a service program called ArrayList which might handle many of your needs.

Buck Calabro
  • 7,558
  • 22
  • 25
  • Agreed - essentially, all elememts in an array are 'used', even if you haven't put anything in it yet... and what if 0 or a blank is a valid piece of data? Like in Java for primitive arrays, you get a default value.... IIRC. Writing my own dynamically-resizing array on a slow day was fun - it was my first time messing with pointer math, and nobody'd told me I _couldn't_ stomp on other processes... Other than the one time I tested it, it never got used though. – Clockwork-Muse Mar 05 '14 at 07:34
  • I actually setup ArrayList yesterday - I have found it very hard to wrap my brain around fixed length everything. I'm glad to see I haven't frustrated you with my many hard-to-answer questions. For the particular arrays I am looking to count, zero and blank and NOT valid data since I am only using them to determine how many distinct values I have. I had backed off of ArrayList because it is so hard to see the data in debug but I will give it another shot today. Thank you for your answer. – Sarah Kemp Mar 05 '14 at 15:12
  • 2
    For debugging, you can brute force via the RPG operation code DUMP. That will produce a spooled file of every variable in the program at the moment it's executed. For a finer touch, I use the SEP debugger with Rational Developer for i. RDi is a great IDE, with an editor, explorer and debugger. – Buck Calabro Mar 05 '14 at 15:57
  • I have not tried DUMP, I have been using SEPs with WDSC 7. I can 'monitor memory' but I can't tell what I am looking at with ArrayLists... just looks like gibberish no matter which option I choose. I will look at DUMP though, thanks. – Sarah Kemp Mar 05 '14 at 16:55
  • 'Monitor Expression' might serve you better than 'monitor memory'. – Buck Calabro Mar 05 '14 at 17:05
1

It's not clear what operations you want to perform against arrays of unknown sizes. Perhaps some example code can provide a starting point, and things can be added or refined as things progress. So, for a trivial example:

 h dftactgrp( *NO )

 D tmp_Ary1        s             10i 0
 D tmp_Ary2        s             10

 d chk_Arrays      pr
 d  ary1                               like( tmp_Ary1 ) dim( 99 ) const
 d  ary2                               like( tmp_Ary2 ) dim( 99 ) const

 D ary1            s                   like( tmp_Ary1 ) dim( 50 )
 D ary2            s                   like( tmp_Ary2 ) dim( 50 )
  /free
        ary1( 1 ) = 12345 ;
        ary2( 1 ) = 'Some value' ;

        callP chk_Arrays ( ary1 : ary2 ) ;

        *inlr = '1';
  /end-free

 P chk_Arrays      b
 d                 pi
 d  ary1                               like( tmp_Ary1 ) dim( 99 ) const
 d  ary2                               like( tmp_Ary2 ) dim( 99 ) const

 d  foundElems     s             10i 0
  /free

   foundElems = 99 ;

   return;
  /end-Free
 p                 E

The chk_Arrays() proc expects two arrays, one is dim(99) with 10-byte character elements and the other is dim(99) for integer elements. But the proc is called with arrays that are both defined as dim(50), and only a single element is populated in each array.

The proc only has a single executable statement. For the most part, the only reason that statement exists is to give a known spot for a debug breakpoint. Compile and run in debug, and display the two arrays when the breakpoint fires.

From there, a description of what else is needed would be helpful.

user2338816
  • 2,163
  • 11
  • 11
  • I want to be able to count the number of used elements in any array (any data type, any length) by just coding something like `myCount = countElems(myArr);` - honestly it should be a BIF... – Sarah Kemp Apr 17 '14 at 15:12
  • In the example code, myCount could be (99), (50) or (1). Which value would you expect to be reported by countElems()? – user2338816 Apr 17 '14 at 23:11
  • myCount should be (1) – Sarah Kemp Apr 18 '14 at 15:27
  • That implies some quality of elements must be detectable to indicate "caller modified" over "caller defaulted/initialized". Unlikely ever to be a %BIF() due to ILE. Caller could easily be ILE CL, COBOL, C or even a DB2 or system exit point. So, it's up to the interface "contract" you establish for your procedure. Your initial example shows "pointer by reference", which tells the compiler there's no need for extra system/compiler assistance. We can assume that you didn't necessarily expect to code that way, but it can be eliminated as an area of compiler assistance. Any new hints for us? – user2338816 Apr 19 '14 at 06:41
  • New hints? I don't understand the question... The idea would be that any value set to zero, blank, or null would not be counted. Ideally the unset elements of the array would all be null regardless of the type of array but I think that is not possible. The problem is essentially solved by the ArrayList Service program mentioned in the accepted answer. – Sarah Kemp Apr 21 '14 at 15:17
  • @SarahKemp By 'hint' I only mean some additional particular way we can determine if an element is "used" or not. In my example code, we can tell that only ary1(1) is "used" because all other 98 elements are zero even when only 50 elements are passed. And we know that only ary2(1) is used because all other 98 elements are blank. That's simply how things work when using CONST on a parameter with DIM() and a mismatch between the dimensions, combined with the default initializations. At least, when both caller and callee are RPG. If another language calls the proc, things can be different. – user2338816 Apr 24 '14 at 11:13