QB64.org Forum
Active Forums => QB64 Discussion => Topic started by: Richard Frost on October 30, 2020, 03:19:05 am
-
How do you folk decide when an array should be dynamic or static? Seems it
was a much bigger problem with QB4.5 because you'd run out of memory with
too many large static arrays, a matter of where they were stored. With
QB64 and modern computers it seems less of an issue. Or is it?
Are the only pros/cons that dynamic can be redimensioned and static ERASEd?
I've been using _MEM to quickly move/copy dynamic arrays, so far with no problem.
Does _MEM care what type they are?
I'd also like to know if it makes any difference to execution speed, but I suppose
I could test that on my own.
-
Good 'ol QuickBASIC restrictions. I had to use $DYNAMIC at the start of my code, just to get enough free memory for it to keep running. Also, there was something else. I think you could use CLEAR , , 2000 to allocate more memory from the stack. I have never had this issue with QB64.
As for speed, I've never had reason to test it, as non-gaming apps just don't have to move that fast, eve in not so quick, QuickBASIC.
Pete
-
There is no reason to ever use static arrays.
-
There is no reason to ever use static arrays.
Well, one reason only: It saves typing two whole bytes. (DIM vs REDIM) :P
Honestly, I don't see why dynamic isn't the default behavior for arrays, rather than static creation. If you never need to REDIM an array, you simply wouldn't issue a REDIM command a second time to change the size of it.
As for _MEM, it doesn't make a bit of difference between DIM and REDIM, as far as its concerned, with one caveat:
If you REDIM an array that has a memblock pointed to it, you'll free that memblock automatically. Trying to reference it at that point will crash your program, as illustrated with the simple demo below:
PRINT i
, x
(i
) 'when i is 2, our value for x(2) should be 123, as that's the value of the 4th and 5th byte in our array. (An integer is 2 bytes each, and we start at byte 0, and I _MEMPUT at byte 4).
_MEMPUT m
, m.OFFSET
, 321 AS INTEGER 'and here we get an error which will terminate our program: MEMORY HAS BEEN FREED. You can't access memory at the old address, when you dynamically moved it around to someplace new.
m
= _MEM(x
()) 'instead, remark out the line above, and re-reference the memory with a new statement, like the one on this line._MEMPUT m
, m.OFFSET
, 321 AS INTEGER 'and then you can get or put the data as you want
-
I always thought STATIC arrays were faster (because they had permanent and perhaps continuous block set aside whereas dynamic gets fragmented like the hard disk), so if you never needed to change the size go with that.
If there is no difference in speed and no potential memory access then it sounds like Dynamic is better.
-
To elaborate a little more:
In QuickBasic, data was either near or far (a consequence of the x86's real-mode segment memory model). Data that was near could be accessed more efficiently because you didn't have to do segment calculations, you just used a 16-bit offset (this is the "DGROUP" you may have heard of). Far data was in a different segment and required a little more work to get at because you had a segment:offset point to deal with. But you only have one DGROUP and it's 64KB (one segment) in size. Most program variables, as well as QB's internal data structures, live there so memory can get tight.
A STATIC array is near, so has its values stored in DGROUP. This makes it somewhat more efficient but uses precious DGROUP space. A DYNAMIC array is far, stored in a different segment so as to not fill DGROUP. In all cases a given array's elements are stored contiguously.
In QB64 there's no segments and everything just gets allocated on the heap, so there's no real difference any more.
-
Thanks a heap for the explanation.
Pete :D
The older I get, the more far memory I use.
-
So you $DYNAMIC fans probably never use ERASE, since REDIM can't be used in SUBs. That means
a loop to fill a numeric array with zeros - or some trickery with _MEMCOPY. The arrays I want
to zero aren't in a time critical section of my code, so the main concern for me is to keep the
line count down and have code that's easy to understand. It's old-fashioned to care about line
count, eh?
Don't ANY of you guys intentionally use static arrays, sometimes? I gotta put "dinosaur" on my resume?
Thanks for the explanation re speed, that it makes no difference, and why. Saves me some dull testing,
because someday this choice will have a bearing on a section of code where speed matters.
-
since REDIM can't be used in SUBs
Wait what?
I don't use $DYNAMIC, I just "DIM" a dynamic array as REDIM myDynArr(new dimensions or old) and that 0's out and that can be used in SUB, who uses $DYNAMIC anyway? why? Isn't it just one of those commands we keep around for old code compatibility?
BTW I don't remember ERASE (for STATIC arrays) from QB4.5 at all, was it used then? Maybe I never needed to zero out an array???
And yes, I use to use Static arrays all the time, but now? thanks to this thread, maybe not.
-
Yes, QB4.5 had ERASE, and like QB64 it was only for static arrays. The issue is re-initializing an
array in a SUB, B+, not creating them. Surely you have to do that, sometimes.
I vunder vot odder commands noboddy usingk. GET/PUT graphics?
I'll follow you experts and also USUALLY use dynamic arrays, exception being when I really want
to use ERASE. Because pencil erasers create employment for some. And I sure hope I'm right in
thinking that arrays dimensioned with variables are dynamic and ones with explicit values are
static, in the absense of the metacommand, so I don't have to do all one or the other.
-
On the issue of clearing a dynamic AND giving it new dimensions here a Lower bound:
myDynArr(i) = i
foo myDynArr()
PRINT i;
":"; myDynArr
(i
),
lb
= RND * 100 - 50: ub
= 51
Just REDIM the array all will be erased.
And I sure hope I'm right in
thinking that arrays dimensioned with variables are dynamic and ones with explicit values are
static, in the absense of the metacommand, so I don't have to do all one or the other.
Nine! Nein
REDIM starts a Dynamic array or re initializes BOTH.
-
Even REDIM dynamic array with same dimensions and all will be erased.
myDynArr(i) = i
foo myDynArr()
PRINT i;
":"; myDynArr
(i
), ' now muddle it
-
in a SUB
in a SUB
in a SUB
Ye kanna REDIM in a SUB
"We all live in a yellow submarine." - Ringo
-
in a SUB
in a SUB
in a SUB
Ye kanna REDIM in a SUB
"We all live in a yellow submarine." - Ringo
Are you saying you want to see REDIM used in a SUB because I've given 2 examples already?
-
Eep. Er. Thought I got an error message saying I could not do that.
Now I'm really confused.
Got it. Sorry I wasn't clear. It's a SHARED array. That's why it isn't
legit to REDIM it in a SUB. Unless I leave off the SHARED. Then what
happens? I find out...
Works fine, which suprised me. Other SUBs can still access it. Duh.
Sorry. I give this entire matter a big rethink. So.....ERASE is really
stupid, REDIM is the better way? ERASE is just for QB4.5 compatibility?
-
Eep. Er. Thought I got an error message saying I could not do that.
Now I'm really confused.
My work is done! ;-))
Yeah REDIM what do ya mean? I haven't DIM it yet! (when you start a Dynamic array.)
-
Eep. Er. Thought I got an error message saying I could not do that.
Now I'm really confused.
Got it. Sorry I wasn't clear. It's a SHARED array. That's why it isn't
legit to REDIM it in a SUB. Unless I leave off the SHARED. Then what
happens? I find out...
Works fine, which suprised me. Other SUBs can still access it. Duh.
Sorry. I give this entire matter a big rethink. So.....ERASE is really
stupid, REDIM is the better way? ERASE is just for QB4.5 compatibility?
Man you are doing my trick adding edits one after the other...
Serves me right I guess.
Sorry about the SHARED adding more mud to the murkyness.
ERASE is for Static arrays that are started with keyword DIM.
Use REDIM to start a Dynamic array (one you can change dimensions but not Type) AND use it to 'erase' ie zero it out or reset strings to "".
-
The only danger in using a REDIM / Dynamic array is if you are doing MEM tricks according to Steve.
Otherwise if DIM / Static arrays aren't any faster than Dynamic then DIM / for Static arrays / ERASE become dinosaur too I guess.
-
This entire post was a lack of knowledge on my part, thinking that redimensioning a
shared array would be illegal, or change the common status, or somehow cause a problem.
It doesn't, and the redim does zero it, unless PRESERVE is used.
Goombye ERASE command, I'm glad to 'ave known ye.
-
Richard - bplus : Thanks for shining a light on this one.
-
Eep. Er. Thought I got an error message saying I could not do that.
Now I'm really confused.
Got it. Sorry I wasn't clear. It's a SHARED array. That's why it isn't
legit to REDIM it in a SUB. Unless I leave off the SHARED. Then what
happens? I find out...
Works fine, which suprised me. Other SUBs can still access it. Duh.
Sorry. I give this entire matter a big rethink. So.....ERASE is really
stupid, REDIM is the better way? ERASE is just for QB4.5 compatibility?
I also tend to go this route:
REDIM Array(1234) AS INTEGER
DIM M AS _MEM: M = _MEM(Array())
_MEMFILL M, M.OFFSET, M.SIZE, 0 AS _BYTE
MEMFILL works as good as ERASE, it’s often faster, and you can customize what you want to fill the default with. (In the above case, it’s CHR$(0) as my fill, but in some cases, CHR$(32) might be more suitable, or even a RGBA value, for a background image refresh.)
-
Richard - bplus : Thanks for shining a light on this one.
Thank Luke for shining the light for me, glad to share the light though :)
And Steve just showed a good use of MEM stuff with a REDIM / dynamic array, so certainly not bad to use _MEM stuff with these arrays just use caution.
Looks safe right after a REDIM or if you know you haven't used REDIM since last MEM check.
-
I'll contribute a little too. I use static arrays where I know that the number of elements in an array cannot change. For example, for icons. The program has a fixed number of icons, there is no need to store them in a dynamic field. Likewise, these fields contain only a handle, QB64 stores its own data for the images somewhere ... and sends us a handle. That's enough.
In order for a dynamic field to be dynamically oversized, it does not have to be SHARED, it is enough if is for the function passed as a parameter. I think this method is more suitable if you are working on a .BM function that will be used in many other programs in the future.
And now the question. I will have a dynamic field. However, I don't want to still write FUNCTION EXAMPLE (ARR () as something) as a function parameter, but I want to pass a handle there. A reference to the address of the field in memory. I'm going to do some experiments with it, because I think _MEM offers this possibility. The notation of the function will then be, I think, clearer, as the commands in QB64 do it.
-
It never would have occurred to me to fill an array with a color, and I forgot about MEMFILL. I'm still
new to using memblocks, and so far have only used them to shift arrays one element to the left.
-
It never would have occurred to me to fill an array with a color, and I forgot about MEMFILL. I'm still
new to using memblocks, and so far have only used them to shift arrays one element to the left.
Yeah, I've got MEM code to copy an array which I am sure will be handy one of these days.