Any way in 2.3 to check whether an array index is defined?

Zephni

Member
I have a 2 dimentional array that is rather large, 65536 in total size.

Its a 256x256 map of 0's and 1's. Don't worry about what its for, its not a level or anything like that.

In another language I could just miss out assigning the 0's so just the 1's exist, saving alot of unnecessary data being written in to RAM. You could then just check whether the queried array index has a value, in gml i'd expect something like:

Code:
exists = is_defined(someArray[220, 56]);
or

Code:
exists = (someArray[220, 56] == null);
But there doesnt seem to be a way of checking an undefined variable or array index like this in gml as far as I can see. This would really save a lot of unnecessary data being stored and is a standard in most languages so wonder what the solution would be in gml?

I have noticed in 2.3 that try catches were added which is great. You could use that like:

GML:
try {
    exists = someArray[220, 56];
}catch(e){
    // doesnt exist
    exists = 0;
}
This will work but just seems a little overkill for a simple check like this, and wonder if its a little slow. Has anyone else got any experience with similar issues in gml?

Thanks in advance for any help :)
 
Last edited:

TsukaYuriko

☄️
Forum Staff
Moderator
Check the sizes of the arrays via array_length. An array cell that will generate a crash when accessed will be at a position that is out of at least one bound.
 
is_array?
That only checks if a variable is typed as an array. Doesn't check the contents of the array at all.

Check the sizes of the arrays via array_length. An array cell that will generate a crash when accessed will be at a position that is out of at least one bound.
That only works assuming the values within the bound are all initialized. What it looks like OP is trying to do is only initialize parts of the array. Say, arr = []; arr[3] = 0; arr[7] = 1;. AFAIK, GM automatically initializes any in-between elements to 0 when you try doing something like that, thus allocating them to memory. There's not really any point to doing that instead of just initializing everything from the start if you're worried about RAM (which you really shouldn't be).

But there doesnt seem to be a way of checking an undefined variable or array index like this in gml as far as I can see. This would really save a lot of unnecessary data being stored and is a standard in most languages so wonder what the solution would be in gml?
Which languages is this standard with? With most of the ones I'm familiar with, arrays are static and the memory is allocated in advance. Anything else requires a separate data structure.

Honestly, 256x256 isn't even a large data set. Do you know how much RAM a 256x256 array would take assuming the worst-case scenario of each element being a 64-bit value? Around 500kB. That's nothing. Loading a single uncompressed sound effect to RAM would take up 10 times that. RAM is so plentiful nowadays that you really shouldn't ever bother optimizing for it unless it's an immediate problem. If you just want to init the array at the start of the game, there is absolutely zero reason not to just do arr = array_create(256, array_create(256, -1));. It's so insanely fast—my tests show it completes in about 0.01 milliseconds—that there is zero need to worry about running it. You could run it literally 1000 times per frame at 60FPS without so much as breaking a sweat.
 

Zephni

Member
That only checks if a variable is typed as an array. Doesn't check the contents of the array at all.


That only works assuming the values within the bound are all initialized. What it looks like OP is trying to do is only initialize parts of the array. Say, arr = []; arr[3] = 0; arr[7] = 1;. AFAIK, GM automatically initializes any in-between elements to 0 when you try doing something like that, thus allocating them to memory. There's not really any point to doing that instead of just initializing everything from the start if you're worried about RAM (which you really shouldn't be).


Which languages is this standard with? With most of the ones I'm familiar with, arrays are static and the memory is allocated in advance. Anything else requires a separate data structure.

Honestly, 256x256 isn't even a large data set. Do you know how much RAM a 256x256 array would take assuming the worst-case scenario of each element being a 64-bit value? Around 500kB. That's nothing. Loading a single uncompressed sound effect to RAM would take up 10 times that. RAM is so plentiful nowadays that you really shouldn't ever bother optimizing for it unless it's an immediate problem. If you just want to init the array at the start of the game, there is absolutely zero reason not to just do arr = array_create(256, array_create(256, -1));. It's so insanely fast—my tests show it completes in about 0.01 milliseconds—that there is zero need to worry about running it. You could run it literally 1000 times per frame at 60FPS without so much as breaking a sweat.
Wow thanks for such a great answer. I guess im thinking of something like PHP that doesnt assume individual default values for arrays.. but yeah C# which uses explicit data types would defualt to 0 for an int array and "" for a string array.

Regarding the memory taken up, my game seemed to use about 4mb etc which is nothing i guess, maybe i am worry too much about tiny details in that way. The array could potentially be 2-4 times as large but even then i guess its not an issue.

Thanks for your help, think i may have been barking up the wrong tree :p
 
Wow thanks for such a great answer. I guess im thinking of something like PHP that doesnt assume individual default values for arrays.. but yeah C# which uses explicit data types would defualt to 0 for an int array and "" for a string array.

Regarding the memory taken up, my game seemed to use about 4mb etc which is nothing i guess, maybe i am worry too much about tiny details in that way. The array could potentially be 2-4 times as large but even then i guess its not an issue.

Thanks for your help, think i may have been barking up the wrong tree :p
No problem! As far as using 4MB, I really wouldn't worry about that. GM idles at around 4-5MB in a blank project. If you've been checking RAM usage with the task manager, it's not very accurate with the runner. You can get a more accurate reading by using the debugger (F6). In my case, initializing a new 256x256 array with zeroes only increased RAM usage by about 10kB, so it seems to be pretty darn efficient.
 

Nidoking

Member
In another language I could just miss out assigning the 0's so just the 1's exist, saving alot of unnecessary data being written in to RAM.
I'm sure this isn't what you're trying to say here, but a 0 takes up exactly as much space as a 1. There's a potential space savings if what you're storing is pointers to data that exists elsewhere and you put NULL in the unused elements of the array, but the NULL takes up as much space as any other pointer. I can't think of a data structure that actually takes up less space while allowing you to fill in arbitrary indices - it would have to have some kind of lookup, which would be horribly slow as a tradeoff.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
I'm sure this isn't what you're trying to say here, but a 0 takes up exactly as much space as a 1. There's a potential space savings if what you're storing is pointers to data that exists elsewhere and you put NULL in the unused elements of the array, but the NULL takes up as much space as any other pointer. I can't think of a data structure that actually takes up less space while allowing you to fill in arbitrary indices - it would have to have some kind of lookup, which would be horribly slow as a tradeoff.
Some languages (such as Lua, JS, and perhaps the aforementioned PHP - been a while since I actively used that) will turn an "sparsely filled" array into a hashtable with integer keys, which is slower than array access but still not too bad.
 

Nidoking

Member
Some languages (such as Lua, JS, and perhaps the aforementioned PHP - been a while since I actively used that) will turn an "sparsely filled" array into a hashtable with integer keys, which is slower than array access but still not too bad.
Maybe so, but doesn't a hashtable inherently take up the entire space for all possible keys? It's at the very time end of the time-space tradeoff spectrum. Again, most of those elements would be NULL or undefined, but they have to have memory locations for the hashtable lookup to find that they're empty.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Maybe so, but doesn't a hashtable inherently take up the entire space for all possible keys? It's at the very time end of the time-space tradeoff spectrum. Again, most of those elements would be NULL or undefined, but they have to have memory locations for the hashtable lookup to find that they're empty.
Not really - the common implementation has it that when you want to assign a value, you calculate a hash (such as a CRC32) of the key, then %= or &= it by the table size, and then perform up to N (commonly 8) steps from that offset to see if there is already key-value pair with that key. If there is, you modify the value in the pair. If there is not but there is a free spot, you store the new pair there. If there is not and there is not a spot (meaning that values are too tightly packed), you reallocate the table to a larger size and spread out the key-value pairs before repeating the process.

See this custom implementation I made for GML a while ago: Map.gml/HashMap.hx at master · GameMakerDiscord/Map.gml (github.com)
 

rytan451

Member
GML:
exists = array_length(someArray) > X && array_length(someArray[X]) > Y && !is_undefined(someArray[X][Y]);
Maybe so, but doesn't a hashtable inherently take up the entire space for all possible keys?
No, it doesn't. Otherwise, every time I initialize a string hash table, with just taking 7 bit 5-character strings into account, I'd already use a full 32 GB of RAM, which obviously isn't tenable.
 

HalRiyami

Member
Using an array to store doubles of 1's and 0's is already wasteful so if all you're storing in the array is 1's and 0's and you're too worried about RAM usage, you should use a buffer instead.
 
Top