Open peterhoglund opened 4 years ago
I would rather prefer to enable the standard pattern from Python:
for _ in range(10):
add_child(scene)
Unfortunately currently _
seems to be forbidden in GDScript, so the proposal may turn into: "allow plain _
underscore for unused variables".
The benefits would be:
_
would probably be the best direction anyway.Also, _
has become the de-facto standard for "not using a variable" in many modern languages (I'm aware of Scala, Kotlin, Rust, Swift, Nim). Maybe GDScript could go a step further like what the Nim language does, and allow _
only for "swallowing" a variable but not for actually using it. Effectively it is not creating a variable binding at all. Maybe this would address your concern:
there is something with introducing a variable that is not used for anything that doesn't sit right with me.
In Nim this would be forbidden:
let (a, _, c) = (1, 2, 3)
# works
echo a, c
# not allowed: `_` isn't a variable binding
echo _
Now you can do this:
for _i in range(amount):
add_child(scene)
or this:
for _i in amount:
add_child(scene)
Some programming languages have special syntax for this case.
@dalexeev You can also use __
(two underscores) as an identifier.
@Calinou The following code
for __ in 5:
print('---')
for __ in 7:
print('*')
will throw the error:
And this will work:
for _i in 5:
print('---')
for _j in 7:
print('*')
With _
, there should be no such error.
Basically, I like for _ in
. But perhaps we should introduce a special syntax for this case. In particular, because in the absence of a variable, the following examples are equivalent:
for _ in 5: ...
for _ in range(5): ...
for _ in range(0, 5): ...
for _ in range(1, 6): ...
for _ in range(2, 7): ...
...
That is, we only care about the number of repetitions. So we could replace "for _ in" with something else. Possible options:
# 1
do x times:
...
# 2
for x:
...
# 3
repeat x:
...
# 4
loop x:
...
Does it harm readability to call the variable _i
or _bullet_number
or _creep_i
vs not calling it anything?
I would rather prefer to enable the standard pattern from Python
I'm not very familiar with Python, but I also think the _
could be a good solution, especially if it is already used by other languages. I agree that it would have to be introduced across the language, for consistency.
You can also use
__
(two underscores) as an identifier.
Is this a common pattern? It seems really hacky and not intuitive at all. I need to backtrack my knowledge of _
(one underscore) to understand why two underscores would be helpful in the situation.
Does it harm readability to call the variable _i or _bullet_number or _creep_i vs not calling it anything?
Not really, I guess. But underscore or not, there is still an unused variable there. You have only solved the problem by sweeping the variable under the carpet by putting the underscore in front of it, so to speak.
I've read that gdscript was designed with ease of use for beginners in mind and managing unused variables and underscores seem to go against that philosophy. To add to dalexeev's list of possible options is a variant of # 1, to only use times
as the key word:
x times:
#do stuff
I've read that gdscript was designed with ease of use for beginners in mind and managing unused variables and underscores seem to go against that philosophy. To add to dalexeev's list of possible options is a variant of # 1, to only use
times
as the key word:
I don't think adding new keywords always makes a language easier to learn. Sometimes, it can be the opposite. Instead, relying on "emergent" feature usage can make more sense (which is pretty much what single-underscore variables are about).
But underscore or not, there is still an unused variable there. You have only solved the problem by sweeping the variable under the carpet by putting the underscore in front of it, so to speak.
And why is it wrong if the whole point of this proposal is getting rid of the warning? It's definitely not worth adding a new keyword or special syntax for this specific case.
I've read that gdscript was designed with ease of use for beginners in mind and managing unused variables and underscores seem to go against that philosophy.
Warnings can be easily disabled. Personally I find majority of them useless.
It's definitely not worth adding a new keyword or special syntax for this specific case.
This is a matter of semantics. All loops are implemented using GOTO.
Personally, I would also add infinite loop (instead of while true
):
# Loop of n iterations
loop 5:
print("*")
# Infinite loop
loop:
...
if cond: break
...
And why is it wrong if the whole point of this proposal is getting rid of the warning?
The warnings are a symptom of the problem, which is that I am being forced to introduce a variable that I will never use. It is an awkward solution in my eyes and it feels like I'm hacking how ´for´is meant to work in gdscript.
As far as I see, it would actually be really easy to add a variable-free for loop with the syntax of for _ in range(x)
, all while not really creating a variable and not interfering with other functionality.
Should I open a PR for this?
@masi456 Feel free to open a pull request for this :slightly_smiling_face:
The documentation on this one seems to be out of date. It says:
Any string that restricts itself to alphabetic characters (a to z and A to Z), digits (0 to 9) and _ qualifies as an identifier.
Going strictly after the doc, _
should be a valid identifier. Maybe this also needs to be updated?
@masi456 It's kind of a special case here. Did you figure out a way to make _
a valid identifier everywhere (e.g. in var
declarations)? If not, we should treat it as a special case and document it in the for
loop documentation only.
@Calinou as far as I saw yesterday, both would be possible, but only implementing it for the special case would be easier. I may need to re-check this. The question is, what would be the preferred way of handling this?
Note that the goal should not be to make _
valid in the sense that it produces a valid variable binding, because GDScript disallows variable shadowing, which would not play well with _
, if it is interpreted as a real variable binding. We should make sure that this works:
for _ in range(3):
for _ in range(3):
print("do it")
By applying the same behavior to normal variable bindings, this would enable a new more concise pattern of discarding return values without having to introduce dummy return variables to silence the "unused return value" warning:
var _ = function_call()
var _ = function_call()
Here it would be similarly more convenient if the var _ = ...
pattern works everywhere instead of having to worry about whether _
is already bound in the scope, requiring awkwardly alternating between var _ = ...
and just _ = ...
Going strictly after the doc,
_
should be a valid identifier.
_
is also used as a pattern in match
. So this is not an identifier.
var _ = function_call() var _ = function_call()
It's better:
_ = function_call()
_ = function_call()
@dalexeev Yes that is a good option as well. Perhaps requiring the var
would be more consistent in case tuple destructuring is added in the future:
var a, _ = returns_pair()
This is fine but it will generate a warning about the 'i' not being used, which quickly clutter up the warnings list.
I think another solution is to just treat the "Unused for loop variables" on the GDScript warnings level (either ignore completely or introduce another type of warning), IMO.
To be honest, the existing warning system makes people come up with various hacks and workarounds on the script level just to avoid them currently, which worsens readability of scripts with enabled warnings...
@Xrayez I would prefer keeping the warning for unused loop variables as it can be used to catch actual bugs in code. I think adding a variable-free loop is a better way to handle the problem here.
The _
syntax is also used in lambdas a lot nowadays. I know resharper really pushes it for unused items.
example: var button_presses_dict = buttons.to_dictionary( b => b.text, _ => 0 )
That may be different parser code, though (Thus a different issue...?)
var amount = 10
for amount:
something()
or will it be unreasonably difficult to implement/parse?
@me2beats I have already suggested this above, as one of the options. I don’t think it’s difficult to implement. The only question is how readable it is and whether it is necessary.
The good thing about this option is that it doesn't require a new keyword.
for i in arr: ...
for i in range(a, b): ...
for i in n: ...
for n: ...
Describe the project you are working on: Platformer game
Describe the problem or limitation you are having in your project: Very often I will use for loops to do the same task several times and not to iterate through data sets. For example when spawning many scenes at once (bullets or enemies). I will use a for loop for this:
This is fine but it will generate a warning about the 'i' not being used, which quickly clutter up the warnings list.
Describe the feature / enhancement and how it helps to overcome the problem or limitation: Introduce a variable free loop for these scenarios. It will work like a normal for-loop only there is no loose variable that is never used. A user will only state how many times the loop will run.
Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams: Something like this:
If this enhancement will not be used often, can it be worked around with a few lines of script?: You can skip the warning by putting an underscore in front of the variable. However, there is something with introducing a variable that is not used for anything that doesn't sit right with me. A variable free loop that basically works as a counter seems cleaner.
Is there a reason why this should be core and not an add-on in the asset library?: Change in gdscript