• 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.

Discussion [Suggestion] ds list / map / grid - quick constructors

gnysek

Member
GMS2 added a great functionality, that you can write:
Code:
var a = [1,2,3,4];
instead
Code:
var a;
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
like it was in all previous GM versions.

So, why not extend it further to other structures ?
I think that ds_list, ds_map and ds_grid can be extended this way easily:

Code:
map = [? "a" => 1, "b" => 2, "c" => "string",5 => sprite_name];
would be same as:
Code:
map = ds_map_create();
map[? "a" ] = 1;
map[? "b" ] = 2;
map[? "c" ] = "string";
map[? 5 ] = sprite_name;
Code:
list = [| 1, "test", 13, sprite_another];
would be same as:
Code:
list = ds_list_create();
list[| 0] = 1;
list[| 1] = "test";
list[| 2] = 13;
list[| 3] = sprite_another;
and for grid (I choose # character as line separator, you're giving it by rows not by columns):
Code:
grid = [# 1,2,3,4,5 # 6,7,8,9 # 10];
would be equal to:
Code:
grid = ds_grid_create(5, 3);
grid[# 0, 0] = 1;
grid[# 1, 0] = 2;
grid[# 2, 0] = 3;
grid[# 3, 0] = 4;
grid[# 4, 0] = 5 ;

grid[# 0, 1] = 6;
grid[# 1, 1] = 7;
grid[# 2, 1] = 8;
grid[# 3, 1] = 9 ;

grid[# 0, 2] = 10;

This should require no change in runner, as this could be replaced by pre-compile part, so compiler gets same code as without this change.

As proof of concept I made a javascript parser which does what I described above. You can update code to see changes (however this is a simple parser, so putting arrays inside ds_xxx or ommiting ; would break it). I understand that for YYG it will took longer than 30 minutes (which I lost on it), since I've added no stacking for substructures and no code editor parsing, but still this seems not that hard to do.

Check it here: https://jsfiddle.net/gnysek/x3c7eL4c/
 
P

psyke

Guest
The ds_list is OK I guess, it looks just like a regular array, but the ds_map and ds_grid looks very nasty and confusing.
I would never use something like that to initialize a ds_map/ds_grid, I would probably create a script with a simple FOR statement.
 

GMWolf

aka fel666
Sure the syntax isn't the best...
But something along those lines would be nice!
Perhaps something like c# for maps?
Maps:
Code:
map = {?
  {"A", 1}
  {"B", 2}
  {"C", 3}
}
And something like this for grids?
Code:
Grid = {#
{1, 2, 3, 4},
{2, 4, 6, 8}
}
 
S

Salvakiya

Guest
you might as well just fix the syntax all together.

Code:
var array = [1,2,3,5,[2,3,5]]; //nested arrays/lists because why do we need both?
var grid = [
    [0,0,0,0,0],
    [0,0,0,0,0],
    [0,2,0,0,0],
]//looks familiar

array[0] = 10
show_debug_message(array[4][1]) //prints 3

var x = 1;
var y = 2;
show_debug_message(grid[y][x])// prints 2

map = {
    "key": 10,
    "otherkey": "somevalue"
}
also you ought to be able to nest maps and arrays/lists in a similar manner

oh and get rid of the array[x,y] garbage. its bad.
 
Last edited:

GMWolf

aka fel666
you might as well just fix the syntax all together.

Code:
var array = [1,2,3,5,[2,3,5]]; //nested arrays/lists because why do we need both?
var grid = [
    [0,0,0,0,0],
    [0,0,0,0,0],
    [0,2,0,0,0],
]//looks familiar

array[0] = 10
show_debug_message(array[4][1]) //prints 3

var x = 1;
var y = 2;
show_debug_message(grid[y][x])// prints 2

map = {
    "key": 10,
    "otherkey": "somevalue"
}
What differentiates the arrays from the lists and grids?
You need the extra character there.
 
S

Salvakiya

Guest
no you do not. lists and arrays can have the same function. grids are literally just nested arrays and lists. YYG just need to implement a proper GC.
 

GMWolf

aka fel666
no you do not. lists and arrays can have the same function. grids are literally just nested arrays and lists. YYG just need to implement a proper GC.
Grids are a different structure to both lists and arrays. They have extra function you know? (Region and disk).

GM does not do any type stuff at compile time (at least, not visible to us).
That means it cannot infer how to parse the literals. We need an explicit way to tell them apart.
 
S

Salvakiya

Guest
right. but this is a suggestion topic. if you look at Lua it has one data type for these things. in fact maps, lists, and grids are all tables in Lua. Lua knows how to handle the data based on what data the user gives it. It is also one of the fastest scripting languages. No reason why a $100 product could not do the same (Lua is free)

there is nothing special about region and disk. you can write a function which will do the same thing to a nested array.
 

GMWolf

aka fel666
. It is also one of the fastest scripting languages
I highly doubt that...
No reason why a $100 product could not do the same (Lua is free)
Plenty of reasons actually. The simple fact lua has had a lot more development...
there is nothing special about region and disk. you can write a function which will do the same thing to a nested array.
There is.
Since GM does not have generics, there is kow way of knowing beforehand if a list contains other lists. Only at run time.
You would also have to check that the nested lists are all of the right size.

Grids are also bounded, lists are not.
 

Zek

Member
Code:
list = [| 1, "test", 13, sprite_another];
would be same as:
Code:
list = ds_list_create();
list[| 0] = 1;
list[| 1] = "test";
list[| 2] = 13;
list[| 3] = sprite_another;
[/code]
Just liked to point out that with lists you can already do:
ds_list_add(list, 1, "test", 13, sprite_another);
Which is pretty similar.
 
S

Salvakiya

Guest
I highly doubt that...

Plenty of reasons actually. The simple fact lua has had a lot more development...

There is.
Since GM does not have generics, there is kow way of knowing beforehand if a list contains other lists. Only at run time.
You would also have to check that the nested lists are all of the right size.

Grids are also bounded, lists are not.
you are missing the point. Lua is free and is capable of this. gdscript uses arrays in the manner I said and I even implemented a grid class using nested arrays. its free and has been in development less time than GM. Both of these are dynamically typed languages.

Grids being bounded is not relevant? My gdscript implementation of a grid does exactly what GM's grids do.

on the topic of performance here is a reference. look for LuaJIT https://attractivechaos.github.io/plb/ note that strings are interned in Lua which makes looking up string keys in a table really fast but the creation of strings will be slightly more costly and there are ways around this.

Lua and LuaJIT are easily embedded... YYG could just ditch GML all together and use LuaJIT =P.

If I did not want GML to improve I suppose I would have the same view and just suggest not to change anything.

edit: YYG's biggest mistake IMO is not breaking compatibility in GMS2 and reworking GML. Now we have a buggy featureless program (but its out of beta!)
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
if you look at Lua it has one data type for these things. in fact maps, lists, and grids are all tables in Lua. Lua knows how to handle the data based on what data the user gives it.
This is actually a pretty bad example, both Lua's and JS' way of organization (implicitly converting an array to hashtable on out-of-bounds-by-more-than-one write) has it that you can quickly degrade performance (by converting a large array to a large hashtable) due to a trivial programming mistake.

All data structures have direct C++ equivalents:
  • ds_list: std::vector<value> (reallocated implicitly)
  • ds_grid: wrapper around value[][] (reallocated explicitly)
  • ds_map: std::map<value, value> (anything can be key, even arrays)
  • ds_stack: std::stack<value>
  • ds_queue: std::queue<value>
  • ds_priority: wrapper around std::list<value> or std::vector<value> (sort-on-insert)
  • arrays: std::vector<std::vector<value>> (rows are reallocated separately; rows can be differently sized; additional logic for implicit creation of arrays on write-to-non-array)
Sure, you can do with just arrays and hashtables, but you'll pay a price for that, and there are pretty good reasons to why multiple collection types were added to the standard library.
 
R

Rusky

Guest
It would still be ideal to get rid of arrays- they can be replaced with a combination of ds_list, nested ds_list, and mmmaybe an automatically resized ds_grid. Their current behavior is pretty wacky and tries to do too many things at once (for example, the precise situations in which arrays are copied vs referenced is not easy to learn).

It would also be good, I think, to get rid of the accessor symbols. GML ought to track the types of ds_ values, rather than relying on the program to specify it at use time. So instead of this:
Code:
my_list = ds_list_create()
my_list[| 0] = 1
use(my_list[| 0])
You would write this:
Code:
my_list = ds_list_create() // or my_list = [| 1], or my_list = { 1 }, or some variation on that
my_list[0] = 1
use(my_list[0])
This has two benefits. One is that it vastly simplifies things like JSON, where you have good reason not to know the type of some value ahead of time, and you can just ask the language, just like is_real, is_string, is_array, etc. The other is that you can write polymorphic code- a script that, say, calculates the sum of values in an array could accept either an array or a ds_list as its argument, as both would support the same [index] operator.

If backwards compatibility is a concern, accessor syntax wouldn't be hard to deprecate and keep around for a while. Tracking the types like that could even let it issue a warning or error when used on a value that doesn't actually hold the corresponding ds_ type.
 

GMWolf

aka fel666
It would still be ideal to get rid of arrays- they can be replaced with a combination of ds_list, nested ds_list, and mmmaybe an automatically resized ds_grid. Their current behavior is pretty wacky and tries to do too many things at once (for example, the precise situations in which arrays are copied vs referenced is not easy to learn).

It would also be good, I think, to get rid of the accessor symbols. GML ought to track the types of ds_ values, rather than relying on the program to specify it at use time. So instead of this:
Code:
my_list = ds_list_create()
my_list[| 0] = 1
use(my_list[| 0])
You would write this:
Code:
my_list = ds_list_create() // or my_list = [| 1], or my_list = { 1 }, or some variation on that
my_list[0] = 1
use(my_list[0])
This has two benefits. One is that it vastly simplifies things like JSON, where you have good reason not to know the type of some value ahead of time, and you can just ask the language, just like is_real, is_string, is_array, etc. The other is that you can write polymorphic code- a script that, say, calculates the sum of values in an array could accept either an array or a ds_list as its argument, as both would support the same [index] operator.

If backwards compatibility is a concern, accessor syntax wouldn't be hard to deprecate and keep around for a while. Tracking the types like that could even let it issue a warning or error when used on a value that doesn't actually hold the corresponding ds_ type.
Oh no.
Arrays a amazing! I would not like to see them go!
They are light weight (compared to ds_*), fast and garbage collected!
Very impoortant too, They have their own type, and are uniquely identified. (Ds_* are indexed right now)
 
R

Rusky

Guest
I mean, I explicitly suggested making ds_lists just as lightweight as arrays. Give them the nicer literal and accessor syntax, track their type, and garbage collect them. The only thing you'd miss from arrays is their wacky reference vs copy behavior, which is only useful if you've got existing code that depends on it.
 

GMWolf

aka fel666
I mean, I explicitly suggested making ds_lists just as lightweight as arrays. Give them the nicer literal and accessor syntax, track their type, and garbage collect them. The only thing you'd miss from arrays is their wacky reference vs copy behavior, which is only useful if you've got existing code that depends on it.
That's true. Fair enough.
 
Top