Passing Returning Arrays Multiple Times To Procs

Discussions about the BBC BASIC language, with particular reference to BB4W and BBCSDL
MattC
Posts: 114
Joined: Mon 16 Apr 2018, 06:17

Passing Returning Arrays Multiple Times To Procs

Post by MattC »

Hi,

I've written a library routine that returns an array that is declared within it, and the array is not declared within the calling routine. However, the library routine is called multiple times and the array is possibly different each time. A very simplified version follows:

Code: Select all

      FOR I% = 1 TO 2
        PROC_MAINPROC
      NEXT
      END

      DEF PROC_MAINPROC
      REM ...
      PROC_lib_routine_A(R%())
      REM ...
      ENDPROC

      DEF PROC_lib_routine_A(RETURN r%())
      N% = FN_lib_routine_B
      DIM r%(N%)
      REM ...
      ENDPROC

      DEF FN_lib_routine_B
      = RND(9)
This causes a 'Bad DIM statement'. If I understand it correctly, the array is dimensioned as a global array (i.e. from the heap?) rather than as a local array (from the stack?). Therefore when the lib routine is called a second time (at least for the next time it is called with a different number of eliments) the error occurs. Question: how can I run this without the error? The 'MAINPROC' does not know, prior to calling the 'lib_routine_A', how big the array needs to be.

I have scanned the Help, Wiki and the forums, and I can't find anything that helps.

Matt
DDRM

Re: Passing Returning Arrays Multiple Times To Procs

Post by DDRM »

Hi Matt,

I'm not sure I can see a solution that allows you to change the array size. In the manual it says you can declare an array and pass it back as you are doing, but that the array you pass in to the procedure call (to "become" the created one) must be undeclared, or, if declared, must have a format identical to the declaration in the procedure. In other words, the call in MAINPROC is going to fail when you change the size of the array in a subsequent call, even if you can deal with the problem within lib_routine_A - which will also fail, since you are re-declaring the same global array.

I wondered if you could deal with the latter problem by using EVAL to create a new array name each time, but unfortunately EVAL won't allow this!

It might be possible to find a tricksy way of doing it by declaring a PRIVATE array (which can be resized within the procedure) and passing back a pointer to it, together with a size. You probably couldn't allocate this to an array within MAINPROC (and if you could you'd still have a problem if you tried to change its size), but you might be able to access the memory directly and get at the data that way.

A less ugly, but perhaps less convenient, way would be to do all accesses to the (private) array through the library procedure - so it would effectively be a gatekeeper (like an encapsulated object - you'd effectively have to use "getters and setters" to access the data).

Otherwise I can't see a better solution than declaring the array once, at the maximum size it could ever be, and then passing a second parameter to tell you how much is actually in use at the present time. If you still want to do the declaration within a procedure, you could use a PRIVATE "used" variable as a flag, so you only declare the (global) array once, and skip over that part once the "used" flag is set.

Don't know if any of that is useful...

D
MattC
Posts: 114
Joined: Mon 16 Apr 2018, 06:17

Re: Passing Returning Arrays Multiple Times To Procs

Post by MattC »

Thanks. Some interesting ideas. I have, at least temporarily, taken the option of using a pre-declared array of a fixed size. This is really only satisfactory as the array is small. However, the possibility is that the array size could be, as I understand it, a maximum of 2^15, which is the maximum number of possible lines in a listbox. Unfortunately, not entirely practical.

Thanks again,

Matt
DDRM

Re: Passing Returning Arrays Multiple Times To Procs

Post by DDRM »

Hi Matt,

Is that really so unrealistic these days? 2^15 is only 32k - for 4 byte integers that's still only 128kb. I often have arrays bigger than that...

:-)

D
MattC
Posts: 114
Joined: Mon 16 Apr 2018, 06:17

Re: Passing Returning Arrays Multiple Times To Procs

Post by MattC »

You're absolutely right, in that it is not unrealistic, nor is it unusual. However, the program I'm writing only needs around 40 max. I'm from an era that is very conscious of space - always trying to find the most space saving way to store data. (I was around 15 when we got our BBC Model B! Doesn't time fly. :roll: )

Matt
DDRM

Re: Passing Returning Arrays Multiple Times To Procs

Post by DDRM »

Hi Matt,

You and me both!

I guess a compromise would be to make it for 40 - 50 max, and stick a check in to give a warning if the program unexpectedly requested more?

If you know the indices will never be more than 255, you could use a byte array, and save 3/4 of the space! :lol:

Best wishes,

D
MattC
Posts: 114
Joined: Mon 16 Apr 2018, 06:17

Re: Passing Returning Arrays Multiple Times To Procs

Post by MattC »

Here's the actual library function I was using:

Code: Select all

      DEF FN_dlg_lbgetitemsarray(D%, C%, RETURN S%()): LOCAL I%, R%, M%: M% = &191: REM LB_GETSELITEMS
      DIM F% ((DIM(S%(), 1) + 1) * 4)
      SYS "SendDlgItemMessage", !D%, C%, M%, (DIM(S%(), 1) + 1), F% TO R%
      FOR I% = 0 TO R% - 1: S%(I%) = F%!(I% * 4): NEXT: = R%
This, at least, allows a limit on the number of elements. I was trying to create a lib function that returned an index FOLLOWING one indicated in the parameters. Hypothetical example might have been:

Code: Select all

      DEF FN_dlg_lbgetnextsel(D%, C%, previous_sel%): LOCAL R%
      SYS "SendDlgItemMessage", !D%, C%, &[value for LB_getselnext?], previous_sel%[, 0] TO R%
      = R%
This would eliminate the need for a local or passed array altogether.

There is a Listview option LVM_GETNEXTITEM getting the next selected one - passing that index back. (And I suppose I could actually change the Listbox to a Listview. Although, that would be rather time consuming - and probably not worth it.) But there doesn't seem to be a similar one for Listbox.

Matt