godotengine / godot-proposals

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

Implement `Array * int` and `String * int` #5126

Open MewPurPur opened 2 years ago

MewPurPur commented 2 years ago

Describe the project you are working on

A game that utilizes a custom resource for SaveData

Describe the problem or limitation you are having in your project

When I have an array with repetitive elements, I have to type it out or use my own function. For example, in a level with 40 collectibles, the default variable with which ones are collected would be [false, false, false, ... false], utterly unreadable. Making my own function is a little better, but requires a bit of mental work, especially if I want to optimize it, and it's not a standardized solution.

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

An * operator inside Array and String would make my code cleaner, more compact, and perhaps more efficient too. Multiplying by X would yield the same as using the + operator to add X of the array.

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

[6] * 0 == []
[6] * 1 == [6]
[6] * 3 == [6] + [6] + [6] == [6, 6, 6]
[6, 9] * 2 == [6, 9] + [6, 9] == [6, 9, 6, 9]
"A" * 8 == "AAAAAAAA"

Multiplying by a negative number would cause a runtime error.

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

I believe it would be used often.

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

Arrays are a core feature.

YuriSizov commented 2 years ago

With Array.map and String.repeat is this really needed? I don't think this improves code quality.

MewPurPur commented 2 years ago

@YuriSizov * could be a shorthand for String.repeat, like + is a shorthand for Array.append_array.

Also, is Array.map related? If I understand correctly, it applies a function to every element of the array, which is different.

YuriSizov commented 2 years ago

Oh, I didn't realize what you wanted from Array * int. That's definitely not what I'd expect that code to do.

MewPurPur commented 2 years ago

I don't see this as any worse than string concatenation and array appending with +. Even without these, I'm in favor of just having an built-in method to arrays with this functionality.

Lielay9 commented 2 years ago

Oh, I didn't realize what you wanted from Array * int. That's definitely not what I'd expect that code to do.

I agree with this sentiment but at the same I can see how it is a little hypocritical since arrays can be appended together with +. Maybe it's something I could get used to.

Though, before creating a shorthand it might be best to include a function for it:


var arr_mult := [1, "a"].repeat(2)
print(arr_mult)
# Output: [1, "a", 1, "a", 1, "a"]
MewPurPur commented 2 years ago

@Lielay9 There is no equivalent of the + operator in method form. append_array() is the equivalent of +=. So if we go in line with that, repeat() in arrays would be the equivalent of *= and not *. Which means this would be half of the functionality in this PR, and not the part I had encountered in my project.

var level1_data = {
   "coins_collected": [false].repeat(30)
   "mushrooms": [false].repeat(4)
}

would not work, for example, it would require *

Lielay9 commented 2 years ago

@MewPurPur I can see where you're coming from and I'm not necessarily against adding the operator. It could be a logical next step after the function. That said, there are multiple other functions that cannot* be done inline, like fill() and reverse(), so it'd be somewhat odd that only appending and repeating can. Of course, every function could just return the array, but that will likely be a reference nightmare.

would not work, for example, it would require *

It's not quite a one-liner, but you can always use a helper function or utilize lambdas if it absolutely needs to be done inplace:

func format_array(arr: Array, repeats: int) -> Array:
    arr.repeat(repeats)

    # Do other stuff

    return arr

var level1_data = {
    "coins_collected": format_array([false], 30)
    "mushrooms" : (func(): var arr := [false]; arr.repeat(4); return arr).call()
}
Calinou commented 2 years ago

I think these operator overloads have a high potential of causing difficult-to-debug issues, so I'd prefer not adding them. This is always a risk when adding new operator overloads, so this needs to be considered carefully for every case.

Also, we already have Array.fill() in 4.0 (also available for PackedArrays).