• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!
  • Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Question - Code Use of array literals

Hyomoto

Member
So, you can now define something
Code:
a = [ 0, 0 ]
And you can nest arrays:
Code:
a = [ [ 0, 1], [ 0, 1 ] ]
The question I have, is how do you then access those nested arrays? The help file doesn't cover it and I was expecting something like:
Code:
var _i = a[ 0 ][ 0 ]
But that doesn't work so the best I can guess is you do something like:
Code:
var _i = a[ 0 ]
draw_text( 0, 0, _i[ 0 ] )
So what is the correct way? Is there another way of accessing a nested array other than assigning it to another variable?
 

FrostyCat

Redemption Seeker
Only the second way with temporary assignments is correct for now. You can make a script to help traverse the nesting, but that's boilerplate work.
Code:
///array_get_value(array, ...)
{
  var a = argument[0];
  for (var i = 1; i < argument_count; i++) {
    a = a[@ argument[i]];
  }
  return a;
}
Chaining array indices was originally branded as a nice-to-have "not in the timeframe of 1.x", along with chained accessors (e.g. json[? 'data'][| 0][? 'name]). I'm curious as to whether that's still in the works.
 

Hyomoto

Member
I hadn't considered the ability to use chained accessors in general, and I wasn't aware that was ever in the timeline, so now I too am curious as to whether or not that is in the works. Thanks for the answer.
 

xot

GMLscripter
GMC Elder
The by-reference @ array accessor only makes sense in the context of writing to an array. It shouldn't be necessary in FrostyCat's script.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
The by-reference @ array accessor only makes sense in the context of writing to an array. It shouldn't be necessary in FrostyCat's script.
Indeed. In fact, on VM it will be slower than regular read, because []-read is assigned a bytecode instruction, while [@]-read is compiled to an array_get call (same as other accessors). array_get, in turn, used to have bugs (returning 0 if argument is not an array) for some time, and I recall someone mentioning that there isn't any real reason to use it under normal circumstances.

Accessor chaining is compiler-side, and I assume that it'll get looked into sooner than later - I was able to implement this for GMLive without too much struggle, for example. The one nasty bit is GameMaker's create-on-write\copy-on-write behaviour, which means that
Code:
arr[0][1] = 2;
must be compiled to (pseudocode)
Code:
if (!is_array(arr)) arr = [];
if (!is_array(arr[0])) arr[0] = [];
arr[0][1] = 2;
but may not duplicate expressions for risk of side effects, meaning that intermediate values may have to be stored somewhere when needed. While on VM this is a matter of smart use of `dup` instruction, on JS/YYC this requires unrolling expressions
Code:
arr[a()][b()] = 1;
// ->
if (!is_array(arr)) arr = [];
var ind1 = a();
var arr1 = arr[ind1];
if (!is_array(arr1)) { arr1 = []; arr[ind1] = arr1; }
arr[b()] = 1;
Things get weirder with post-increment/post-decrement;
There is also a thing where
Code:
func()[index] = value;
would not be possible to correctly compile with create-on-write rules at all, since the original location for newly made array to be assigned to would be undetermined.
 
Last edited:

Yambam

Member
but may not duplicate expressions for risk of side effects, meaning that intermediate values may have to be stored somewhere when needed. While on VM this is a matter of smart use of `dup` instruction, on JS/YYC this requires unrolling expressions
Code:
arr[a()][b()] = 1;
// ->
if (!is_array(arr)) arr = [];
var ind1 = a();
var arr1 = arr[ind1];
if (!is_array(arr1)) { arr1 = []; arr[ind1] = []; }
arr[b()] = 1;
This looks exactly like my implementation of arrays in my interpreter. I see some strange things on the last lines though, wouldn't it need to be something like this?
Code:
if (!is_array(arr1)) { arr1 = []; arr[ind1] = arr1; }
arr1[b()] = 1
Things get weirder with post-increment/post-decrement;
There is also a thing where
Code:
func()[index] = value;
would not be possible to correctly compile with create-on-write rules at all, since the original location for newly made array to be assigned to would be undetermined.
How would the original location become undetermined? o_O
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
I see some strange things on the last lines though, wouldn't it need to be something like this?
Code:
if (!is_array(arr1)) { arr1 = []; arr[ind1] = arr1; }
That is correct. I was a bit too quick to add that example after originally posting. Edited now.
How would the original location become undetermined? o_O
Say, you have a script do
Code:
return argument0.some;
If `some` is not an array, it is returned by-value rather than by-reference, meaning that you can't reassign it at original location in the instance from outside the script because you don't know that it is stored in an instance as such. While C++ allows to pass a pointer to the variable, on JS your only solution would be to "box" all values in arrays or small objects, which is unreasonably costly.
 

Hyomoto

Member
Interesting stuff. I think it would be fair to say we could probably live without accessor chaining on function returns, even if that would be 'moar powerful'. I use a lot of nested data types, so the ability to do this is obviously something I'm particularly interested in. I've been giving GM2's nested arrays a good workout. I like to code in such a way that information is easily removable or addable to the source and so using databases of information has been something I've spent a lot of time fooling around with lately and typically I'd use ds structures, but you run into issues where a ds_list -might- be perfect if it were a ds_grid, but a ds_grid is too rigid and the only way to add data to maps which have their own fun uses is to add another data structure like a list. Being able to use nested arrays is wonderful, but it highlights exactly why accessor chaining would be entirely desirable. I've lived without it this far so working around that is hardly anything new, but news of its implementation would probably make me need a sick day. I got pretty excited for nested arrays and ternary operations.
 
Top