godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Python-Like For-If-Clause for initializing GDScript's Arrays and Dictionary #3186

Closed Lucrecious closed 3 years ago

Lucrecious commented 3 years ago

Describe the project you are working on

I am working on a platforming game, although this feature can be used for many, many different things.

Describe the problem or limitation you are having in your project

Often, I would like to filter a list on the fly without having to write a for-if loop.

Filtering an array by type:

var areas := []
for child in get_children():
    if child is Area2D:
        areas.push_back(child)

Filtering an array by some condition:

var numbers := range(100)
var evens := []
for i in numbers:
    if i % 2 == 0:
        evens.push_back(i)

Describe the feature / enhancement and how it helps to overcome the problem or limitation

In Python, there is a for-if-clause syntax to initialize a list by iterating through another and picking and choosing what you want.

This turns very common 3-line boiler plate code into just 1 readable line of code.

In Python, filtering array by type:

areas = [child for child in get_children() if child is Area2D]

In Python, filtering array by some condition:

numbers = range(100)
evens = [i for i in numbers if i % 2 == 0]

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

A similar feature in GDScript would be pretty nice, and it could look something like this:

Filtering array by type:

var areas := [child for child in get_children() if child is Area2D]

Filtering array by some condition:

var numbers := range(100)
var evens := [i for i in numbers if i % 2 == 0]

This feature could also be used to initialize values:

var evens := [ i * 2 for i in range(100) ]

var grid := [ Vector2(x, y) for x in range(3) for y in range(3) ]

var collision_shapes := [ collision for child in get_children() \
    for collision in child.get_children() if collision is CollisionShape2D ]

Could also be used to initialize a dictionary in similar ways:

var name_to_child := { child.name : child for child in get_children() }

Here's a draft PR, it has a couple bugs but with some help it shouldn't be too bad. Of course, I'm happy to revise anything contributors want me to revise. https://github.com/godotengine/godot/pull/51997

If this enhancement will not be used often, can it be worked around with a few lines of script?

Yes, the workaround is simply to write a for-if loop to initialize the array or dictionary. However, I feel this would be used often enough to warrant a shortcut.

Is there a reason why this should be core and not an add-on in the asset library?

It's GDScript.

AaronRecord commented 3 years ago

I'm pretty sure this is a duplicate of https://github.com/godotengine/godot-proposals/issues/2972 (https://github.com/godotengine/godot-proposals/issues/2972 doesn't specifically mention dictionaries but it's the same idea)

Lucrecious commented 3 years ago

Darn it! Thanks I looked it up but I didn't see it. sigh Although, this one is a bit more comprehensive and I've attached a draft PR.