Hi Lim,
<SOAPBOX STATE="ON">
Why do you want to dynamically allocate such a small array?
Is there a good reason why the array is being allocated in the procedure 
instead of by the caller?  Normally, you want storage management to be 
done by the caller.   The exception is when the storage management is 
significantly complicated, and therefore needs to be encapsulated.
In my opinion, dynamic arrays do more harm than good.  They make 
programs more complicated than they need to be.  They make the 
programmers concentrate too much on infrastructure, and that takes away 
from their ability to concentrate on the business logic.
They also require extra code to re-size and re-allocate the array, and 
that code takes extra CPU time.  The performance hit is usually not 
significant, but why incur the extra CPU time if you don't have to?
I mean, think about it... your array is only 640k of memory.  That's 
barely more than half a megabyte!  Your system will never notice that 
memory.  There's probably a thousand other things on your system that 
are wasting more storage than that.  Think about it:  the i uses both 
disk and memory in the same address space...  "Single level store" they 
call it.  That means that every disk object you haven't cleaned up, 
every spooled file you haven't cleaned up, etc, is taking up storage 
just like your array is.  Any one of them is probably more than 640k! 
Why would you want to add the complexity of a dynamic array to save a 
few kilobytes?
Also storage management inside a procedure to be passed back to it's 
caller is usually a mistake.  That means every time the procedure is 
called, you must always reserve new storage.  you can never re-use 
existing storage, since the caller would have to be in control for that 
to happen.  It also places an onus upon the caller to make sure they 
deallocate the memory, making your routines more cumbersome to use, and 
requiring your caller to know more about how your routines work.
Furthermore, it requires you to pass a pointer to the procedure, which 
means the compiler can't help with error checking on the parameters.
Let's say your dynamic list is a list of employees to be returned from 
an employee master file.  I would suggest putting THIS in the copy book 
for your business logic:
     D EMPLOYEE_NAME   S             20a   based(Template)
     D EMPLOYEE_getList...
     D                 PR            10i 0
     D   piKey                        4a   const
     D   piList                            like(EMPLOYEE_NAME)
     D                                     dim(32767) options(*varsize)
     D   piMax                       10i 0 const
The idea is that the caller will provide an "employee list" array, and 
you will populate it.  (instead of you generating the array dynamically).
Since the procedure doesn't want to make any assumptions about how big 
that array can be, it allows for as many as 32767 employees to be 
returned.  However, it also specifies options(*varsize) so the caller 
can pass a smaller array if it wants to.   Then, piMax is passed by the 
caller to tell the procedure how many elements (at most) can be placed 
in the array...
The routine then looks like this:
     D EMPLOYEE_getList...
     D                 PI            10i 0
     D   piKey                        4a   const
     D   piList                            like(EMPLOYEE_NAME)
     D                                     dim(32767) options(*varsize)
     D   piMax                       10i 0 const
     D  x              s             10i 0 inz(0)
      /free
          setll *start EMPLMAS;
          read EMPLMAS;
          dow not %eof(EMPLMAS);
             if (x >= piMax);
                // error -- out of array space.
                return -1;
             else;
                x = x + 1;
                piList(x) = EMPNAM;
             endif;
             read EMPLMAS;
          enddo;
          return x;
      /end-free
     P                 E
The code uses piMax to verify that it hasn't overflowed the array. It 
simply loads the array elements, and an IF statement verifies that it 
hasn't exceeded the size of the array.   When all is done, it returns 
the number of employee names that it found in the file, or -1 if an 
error occurs.
The caller may not want 32767 names... maybe it only wants 100 at most, 
so it could do the call like this:
      /copy WHATEVER
     D names           s                   like(EMPLOYEE_NAME)
     D                                     dim(100)
        count = EMPLOYEE_getList('key': names: %elem(names));
        if (count = -1);
           // handle error
        endif;
No need for a dynamic array or dynamic allocation of elements...  No 
need for the procedure to handle all of the allocation for the caller, 
or for the caller to remember to deallocate the result...
</SOAPBOX>
Okay... now that I've finished protesting :)
Why do you think your way doesn't seem safe?
Lim Hock-Chai wrote:
is there a way to safely return a dynamic array from an export procedure
to the caller?  Something like below just doesn't look very safe for me.
 
P getListInDynaArray...            
D                 pi               
D  piKey                         4 
D  piRtnListDynaArray...           
D                                 *
D myDynaArray     s             20    dim(32767) based(myDynaArray_p)
 /free
  myDynaAry_p = %alloc(200);
  . . . 
  piRtnListDynaArray = myDynaArray_p
 /end-free
As an Amazon Associate we earn from qualifying purchases.