YoYoGames / GameMaker-Bugs

Public tracking for GameMaker bugs
26 stars 8 forks source link

Add "foreach"-like construct to GML #3203

Open Alphish opened 1 year ago

Alphish commented 1 year ago

Is your feature request related to a problem?

People keep hijacking my suggestion about "with" working with arrays as if it was mutually exclusive with "foreach" and, to my best knowledge, didn't make a feature request of their own. ^^'

More importantly, it would be really nice to have a cleaner way to iterate over an array, as opposed to somewhat verbose for (var i = 0; i < array_length(_array); i++) { var _item = _array[i]; ... } or context-losing array_foreach(_array, function(_item) { ... })) (and still verbose if you need to pass local variables into method).

Describe the solution you'd like

The most popular solution I've seen mentioned is a syntax like foreach (var _item in _array) { ... }, used e.g. in languages like C#.

Another potential syntax would come from JavaScript, like for (var _item of _array) The distinction of JavaScript syntax is pretty important, because in JavaScript for (var _item in _array) means something different altogether (it iterates over object properties instead of array items). And GML seems to take inspirations more so from JavaScript rather than C# lately (e.g. using array_filter/map/reduce as opposed to array_where/select/aggregate).

It would be even better if we could define our own foreach-compatible iterable types, some way or another (possible in both C# and JavaScript).

Describe alternatives you've considered

The addition of closures as described in this issue would make array_foreach a lot less verbose when using parameters from the outside. However, I still think syntax like for (var _item of _array) { ... } is a lot friendlier than array_foreach(_array, (_item) => { ... }) (less risk of misplaced parentheses, too).

Additional context

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of

katsaii commented 1 month ago

I would prefer not follow the JS syntax (please, let's not have have both for..of and for..in) because it's confusing. It does not follow the idiom from basically every other language that has iterators, where the iterator iterates over the values of the container, not the keys.

We should learn from JS, and stick to:

for (var val in [1, 2, 3]) {
  show_debug_message(val); // prints 1 2 3
}

for (var val in { x: 1, y: 2 }) {
  show_debug_message(val); // prints 1 2
}

(No foreach, so we're not introducing new keywords.)

And then for iterating over keys/indices we should:

var arr = [1, 2, 3];
for (var i = 0; i < array_length(arr); i += 1) {
  show_debug_message(i); // prints 0 1 2
}

var stc = { x: 1, y: 2 };
for (var name in variable_struct_get_names(stc)) {
  show_debug_message(name); // prints "x" "y"
}