I don't mind "in 100". People are saying it's cursed but I'm just glancing over the docs now and
`for in 2.2:`
which is apparently the same as
`for in range(ceil(2.2)):`
seems way more cursed imo.
edit: Turns out it feels cursed but is actually right:
`for i in ceil(2.2):`
becomes:
`for i in 3: # prints "0, 1, 2"`
Alright, so I actually opened an issue over the doc and I was wrong. We were both correct in assuming that "2" should be the last value. "ceil(2.2)" pushes up to "3" and therefore will print "0, 1, 2" which is actually correct. Seems odd at first! But it \*is\* correct.
edit for clarity:
`for i in ceil(2.2):`
becomes:
`for i in 3: # prints "0, 1, 2"`
It drives me crazy, because you actually _should_ use the ridiculous syntax. `range(100)`, unlike in Python, actually constructs the full 100-element array in memory and then iterates it, whereas just throwing the number in the `for..in` clause iterates without allocating any extra memory. This can be significant from a performance standpoint if your loop counter is large.
Yeah, Python does it right and has a nice abstract "iterable" interface. But you can try it yourself. I'm running Godot v4.2.1 right now and `print(range(100))` prints out a massive array.
Funny thing is, Godot actually has a fully-working iterable interface. So you _can_ write a proper `range` class by defining methods called `_iter_init`, `_iter_next`, and `_iter_get`. But as far as I can tell, this capability is completely undocumented. I only know about it from poking around in the source code.
Bullshit. range inside a `for in` statement is optimized away. It does not allocate an array.
It literally takes a few seconds to test this yourself. You gain nothing by spreading misinformation. Why would you do that?
Go type in this:
for i in range(2_000_000_000):
break
If range would allocate an array, the engine should crash because it's trying to allocate a huge array (60+ GB due to the size of a Variant). Even if it could, it should be blocking for a long time to do that. Well, does it?
Or go ahead and print the memory usage inside the loop. It barely increases compared to outside the loop.
Yeah, but then we add some smaller ones, all over the complex shape. If calculus has taught me anything, it's that you can fix anything with enough small pieces.
I like ABAB, because AABB is a fairly basic rhyme scheme, while ABAB allows the lines to interweave more expressively in the time they are allowed to unfold, before being shoehorned back into the confines of the rhyme.
Why is it bad design? It seems unambiguous and in line with Python’s syntax philosophy (emphasis on philosophy, not actual Python syntax), but maybe I’m mistaken or missing something. I don’t know much about designing languages.
Python syntax does not support that, and usually when you write **in** keyword, it usually implies in some **container/collection** that stores multiple values that you can iterate on.
So when you write that you iterating something **for/while** usually it continues with some collection that you are iterating over, and not some number, which from usage and from any other perspective that you can think of, it does not make sense.
when you specify **range(),** it's generator, it's like stream of values, or a collection that you iterate over, but do not store the whole thing in memory, still it is some stream of items that you will iterate over, overtime.
Yes, I know in Python the \`in\` operator takes an item as its first operand and a sequence as its second operand and checks if the item is in the sequence. In GDScript the \`in\` operator can also optionally take an integer as the second operand and create the implied sequence of numbers. It's more concise, it's unambiguous, and I think it's completely clear what it means.
I would be interested to hear why the Godot developers made the choice and whether they would do the same designing Python or if they think its specifically useful for GDScript.
Edit: Oops I started talking about the \`in\` operator but we're talking about the for statement which is different. Sorry I just woke up. But I think my point remains the same: replacing a sequence with an integer that implies a sequence doesn't make the statement less clear.
I know how it works in Godot, but it breaks consistency compared to any other language that supports loops, it's very ambiguous, since loops are for iterating some values, and not iterating over integers.
What are you iterating over in integer? The bits of the integer?
Completely ambiguous.
As a freshy programmer, the "for i in 100" clicked and made sense to me, so its possible it's an ugly cursed line of code, that just makes it easier for noobs to get through a common pitfall.
I do understand the ambiguity of it tho, and I would avoid it if I knew better.
That being said, I wonder if I unintentionally have similar lines in my projects, due to how intuitive it would feel (as a beginner) to write it out that way, and it just so happens to work so I wouldn't necessarily know it was the "wrong" way to approach.
I know that it is targeted towards beginners.
I know that beginners prefer shorter code, but there is a limit to sacrifice ***correctness/logic** over **code elegance**.
As I mentioned in other comments, we already saw in Javascript that when you allow a lot of such hacky/elegant blocks of code, if you don't know what you are doing, it can become quickly big mess of code and impossible to debug.
I don't claim that this feature would necessarily produce that, but multiple such features, it would create a ton of bad practices.
Also, it can cause overlooked bugs.
It's targeted towards anyone who written a loop that runs from 0 to N - 1.
Javascript is not elegant at all. This loop shorthand has nothing in common with the bad parts of JS. JS has no such shorthand and its issues stem from the dynamic nature, truthyness and nulls.
Stop being condescending.
It’d give me red flags for the entire language if they had syntax solely for iterating over the *bits* of a number, I’ve never heard of any syntax that does that, or what the justification would be for having syntax for such an esoteric use case. Are there any examples of languages that provide syntax for that already?
Well you're saying it's completely ambiguous with only one suggestion for an alternative interpretation that u/Potterrrrrrrr is explaining doesn't really make sense.
I'm not saying that it is ambiguous only because it can be interpreted as "iterating of bits of the integer", it is because it can introduce bugs, bad practices for beginners, inconsistency with other languages, also someone might think it is for iterating (1, 100) or (0, 100) including 100, it loses the purpose of the syntax.
I already have seen beginners make trivial mistakes even with Python syntax, let alone this monstrosity.
It sacrifices clarity for elegance even tough most people can deduce why it is used, with scale it can quickly introduce overlooked bugs.
I know, your point was that it was ambiguous but ambiguous with what? Your example was iterating over bits which you’d never do and if you did you wouldn’t reasonably expect the language to have syntax for that. Can you think of an example that is valid that would actually make this syntax ambiguous? Of all the syntax to argue against, I’d never have thought that ‘for i in some_integer’ would be the example that’s contended. The only ambiguous part to me is what the initial value is, which quickly becomes unambiguous when you’ve written more than a handful of for/range loops and realise 90% of them start at 0. Genuinely just curious on your thoughts, I think this syntax is a nice, readable way to cut down on boring boilerplate.
Personally, I don't like odd edge-case/shorthand syntax like this in languages just because it's one extra thing to keep track of, and it doesn't have as much universal application.
`range(0, 100)` can be used unambiguously throughout your code anytime you need a range of values. As long as you know what the range function does you can easily understand the logic wherever it's used.
`for i in 100` on the other hand is only really useful in loops. It's probably not really allowed anywhere else, and if it is allowed it's not very readable (`if i in 100` sounds even more cursed because ranges aren't quite as implicit as for loops). So you likely won't use this syntax too often, and in 6 months or a year when you revisit your code, you'll probably have to remind yourself that it's the same as `for i in range(0, 100)` anyways. At that point, you may as well cut out the middleman and use the more explicit syntax
That makes sense. I use `for i in range(100)`, and I don't think I'll switch after learning this syntax. But I also feel like when all of us saw `for i in 100` we knew exactly what it meant, and the Godot team seemed to think it was a good idea so I'm trying to give it the benefit of the doubt. But as another comment pointed out, someone might think it's iterating through the bit sequence of the number rather than a range, and I get why people don't like it.
>someone might think it's iterating through the bit sequence
Nobody would think that given GDScript is a high level scripting lang, and even if it wasn't, that idea is nothing more than a sweaty attempt at trying to come up with some possible misinterpretation, it's fine as long as it's a joke.
Good point. Looking over these threads it seems like that johny james fellow who made the comment about bit sequence is a bit of a pedantic fool. And your comments overall have affirmed my initial perspective that ‘for i in n’ is not bad syntax design.
It's a bit cursed when it's just a straight into, but it's kinda nice when you need to loop based on a variable. It's less verbose than using a full `range()`
True that.
Although saying it's my primary language would be a lie. Since last august I have been primarily working with sql, qlik and a little python.
I guess you could say C++ is the program I learned first
I am aware of that and I would use it for integers, but for floats I prefer the pow function as floats only approximate the literals. Though, last time I mistyped it and ended up with 64 instead of 2^32 that took me a while to fix, so I personally find pow notation more robust to mistakes.
AAAA master race.
I spent too much time with C++ and Java. Gdscript feels so refreshing because you can write short readable expressions that almost read like a concise English sentence. I'm not giving that way!
I feel that. I was using C# a lot with Unity but started using Python for other projects. Every day I like Python more. Going into Godot I thought I’d use C# but I learned GDScript on a whim and it’s so nice.
but but bro you're gonna forget the syntax of the language you're using if you're away for a month or two! just keep using the verbose C-family style!
/s
BAAB
B, because it shouldn’t look the same as a for loop.
A, because it is easier to read and debug.
A, because I would use range to show I am using an unusual range.
B, but only because it is less prone to typing errors.
The only part I don't like of A is \*\*. And I'd probably be fine with it if I used it more often.
Maybe for i in range(0,100) explicitly gives me start and end points, while i in 100 seems very... undefined.
Came to the comments to say this lol. I have seen bugs in production C++ code because of this. It is at least consistent that "and" is "higher priority" than "or" but I find relying on that very unclear.
While looking up the GDScript operator precedence I was surprised to find that the docs recommend "and", "or", and "not" over "&&", "||", and "!" which I personally don't like ESPECIALLY because they don't offer an alternative to "!=" so I don't see why they would discourage "!".
Clearly, you should write `not(a == b)` /s
Personally I've come around to `or` and `and`, but `not` is still very odd... especially the cursed `if a not in b` syntax for `!b.has(a)`.
I actually debated between both of these in my head a lot, I think my actual conclusion is that both of them are sufficiently readable/clear and I wouldn't have an issue with either option.
That being said, just for fun I'll give my answer for each one:
* \#1: A. I was strongly leaning towards B, but if I were to set one as the "standard" across my codebase I'd prefer A specifically for "not" cases. "x not in []" is much cleaner than "![].has(x)" and IMO "in" is just as clear of a keyword as "has" anyways
* \#2: B. But this one is so close that I actually don't mind either. I just like B slightly more because it's more natural to me based on my previous languages I've worked in
* \#3: B. Your future self will thank your past self for explicitly stating ranges lol
* \#4: B. Similar idea to #3. When you inevitably take a break from your project and come back to it 6 months later rusty as hell on GDScript, you'll probably prefer the immediate clarity of pow(x, y) over x ** y
one thing i do like about `x ** y` is it reads a little clearer to me what the base and exponent is. not sure if that's enough to overcome the advantage you mention, but it's something.
knowing that gdscript doesn't have generators both versions of the third option would give me pause, because id be afraid it's going to allocate an array. does anyone know if either is special cased to not do that in for loops?
`range()` returns an array only if used outside of for loops. When used in a for loop's `in` statement, it doesn't allocate an array, it's converted to a boomer loop under the hood.
`in range(0, n)` is still ugly though.
well that's rather unintuitive...
>in range(0, n) is still ugly though
i don't think it's particularly bad, though i would want it written `in range(n)` when the beginning is zero. for me the ugly part is that iterating over ranges beginning at 0 has a special syntax that doesn't conceptually relate to the way you do other kinds of ranges. generally im of the opinion that if you're going to do a special range syntax for integers it should naturally extend to beginning/end and ideally also stride. otherwise it's just pointlessly inconsistent.
Do you have a source? According to Godot's documentation, using `for i in n` is "similar" to `for i in range(n)`
https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html
Yes, the documentation I found doesn't contradict what they said, nor does it affirm it. That's why I want to know their source.
Edit: also I noticed you said in another comment that the shorter syntax probably bypasses array allocation--and it does, but so does using the range function according to the documentation I linked.
1:B. Having the keyword `in` have different meaning in `for` vs `if` can easily be confusing. Using "has" makes it clear that this is a function on an array.
2: A. Since the keywords `and` and `or` exist, they might as well be used. They are a bit morereadable than `&&` and `||`.
3: B. I think A was just added to Godot for performance reasons, but I think this doesn't really matter much in Godot 4. Although it should be `range(100)`.
4: B. Unless you are using powers a lot, then having an extra operator just for this is unnecesary.
Isn't readibility meant to provide clarity?
That being said, IMO, the clarity (right) one is more readable and clear than the left.
(Except the Boolean operators, I prefer the left)
The ‘or’ statement can be simplified btw. Not sure if real code or just an example but if x is 0 then it’s never 1. Checking if it’s not 1 is unnecessary.
Which do you prefer? Whatever makes the code readable not only to myself 6 months from now but also to others. Generally speaking, unless you’re targeting a platform where you need to be concerned about brevity, I find it is always better to be more verbose as it makes the code more understandable.
So, it comes down to what makes the most sense to you from a legibility perspective.
Didnt know A1 was possible
In gdscript i think A2 makes the flow of coding better
I use B3 if the start value of the range is not zero, A1 otherwise
And I only remember using pow, so B4
spaces 🤭
but seriously, ABBA. I prefer named booleans when writing conditions so && / || reads a little better and I've been programming for 13 years and I'm just used to it.
and the range thing only works for a range that starts at 0 I'm guessing, so if you use the shorthand, it will be inconsistent with other ranges.
that being said, I think I'd defer to the group I was working with. it's not that important to me compared to aiming for a cohesive codebase
The funny thing is that BAAB is what I know is the better choice (though range is suitable too), but there is something I always find charming about line 2 of B. Maybe it is the C++ apologist in me. Also, catch me doing \*\* all the time anyways.
I use Elixir in my day job and it reads exactly like A, so I write that on accident. Helps so much that I forget I’m switching between languages and will either leave off “var” in Godot or write “var” at my job
BABA opinion
B1. This is more human readable to me. We’re are checking “does the list have the element x” instead of “is the element x in the list of”
A1. words over characters every day, every time.
B2. Depending on whether we’re dealing with array of integers or a n array of object, I’ll switch between either
A2. This notation is far more common
What's the difference between improve readability versus improves clarity?
That aside, A should run faster as it is using built-in operators so I would prefer A.
BBAX
1. B, because this could be defined as a variable somewhere else, and I prefer chaining functions, so ".has(...)" would be my intuitive approach
2. B I come from C++ and other langs, that used the operators, instead of keywords. It's just a preference tho
3. A honestly I havent seen this syntax anywhere else, but this is way more confortable to write in most situations, where you just go from 0..n, and it can also be a variable, or a .size() for expl
4. Depends on situation. I also prefer n*n over n**2 or pow(n, 2). I'd say I would use ** when raising to an integer constant, but pow(a, b) when using a variable as a power, or a float
Reading through the other comments, this seems unusual, but I prefer it this way :P
I like a mix of the two honestly. I always prefer keywords to be complete real words, easier for my dyslexic ass to quickly see things and parse information. The less symbols the better for me.
and + or having syntax highlighting is more clarity than && + || without highlight for me.
Everything else aren't different enough to be that big of a deal imo.
For consistency's sake, I often fall back to official docs on these matters. Godot way is fast to write and looks less cluttered, but the other way is more standard to general non-Godot conventions. Everyone makes their own choices, I just try to be consistent per project.
BBBA for me, with caveats. I'm wondering if `Array.has()` is less performant since it adds a method call to the stack and `in`... *might* not?
I also am not entirely decided on whether I prefer `not`, `and`, `or` to `!`, `&&`, `||`.
For the second item, you shouldn't chain comparators like that.
Instead, either make a function that takes the arguments as inputs, and within the function do it in simple statements, or simply do it before this code and make the result what you test.
A good rule of thumb; ONE is always fine (x > y), TWO is OK, as long as it's pretty simple and you can clarify with parentheses if needed (X > y > z) or ( (x > y) && z ), but if it's more than that, break it up:
```
a = x > y
b = w == z
c = x != 42 && y != 24
check == a && b && c
```
From my tests, `range` is significantly slower (like, over twice as slow), as it has to allocate an array to be used. This may also worsen memory fragmentation over time if used constantly.
Always prefer `for i in 100:` where possible.
Furthermore, using `and` and `or` just makes more sense. It helps distinguish comparison operators from the very similar-looking bitwise operators.
I want to make a comment about the 3rd case. It's an odd one because while I would always use A, I would never write it that way and I'm sure a ton of people aren't realizing that they use A more than B.
It comes down to magic numbers, numbers where no meaning can be immediately gauged from them, and how giving meaning to them makes things more readable.
While many would not think this looks normal:
```
for i in 100:
```
I believe there are many out there who might do something like this to get indices:
```
for i in array.size():
```
And both are the same, one just has their magic number being given meaning.
And if my range has a non-zero starting point, I'd find it more convenient to add an offset than to state the range still:
```
for i in NUM_OF_ALPHABETS:
var char = i + CHAR_OFFSET
```
Though, I can never be sure of other's opinions and would like to open the question to those who have said that B is what they'd prefer to use. Do you still use B more often, or has my comment made you rethink your decision?
This from UX is very bad and it breaks consistency with any single programming language.
When you are using loops (for, while) you are usually iterating over something (collection, stream of values), it is some construction that contains multiple values, which does make sense in terms of loops and iteration.
But when you state single number and say **x in SOME\_NUMBER,** it really makes zero sense.
What's inside **SOME\_NUMBER,** it can be confused that you are iterating over the bits of the number or something else.
It's absolutely ambiguous.
Every language has its own rules and caveats that you can choose to learn. While it may not make sense in another language, it is an [explicitly expressed way to use the for loop in GDScript](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html#for).
To say it's absolutely ambiguous is to ignore the documentation which also point out these things like the maximum and minimum values of `int`s or the fact that floating point numbers have blind spots in their representations. While it's understandable that someone can say, `int`s should be as big as we need them to be, or `float`s should be able to accurately represent every number within their range, that's just not the idyllic programming language we have.
But, *you* should use what you or your team believe to be is the clearest way to convey your code. Ultimately, consistency is the key.
Godot developers allowing such functionality does not make something unambiguous.
I know it's in the docs, I know that it replaces range, but I'm simply saying the design decision that devs made was poor and contradictory to any other programming language.
Also, it breaks the concept of **for** loops, it is about iterating over some values, and with that syntax, you are iterating over what? An integer? How can you iterate over integer?
It's one thing to allow it. It's another to decide to use it.
It's similar to Javascript and all its monstrosities that it delivers.
It invites bad practices and even more useless abstractions.
>This from UX is very bad and it breaks consistency with any single programming language.
Not really and no, many programming languages have no for loops to begin with, and even if every single language didn't contain this syntax, it would not be a valid reason not to have something. There is a reason why people create new languages and it's not to have the exact same thing as something else.
>When you are using loops (for, while) you are usually iterating over something (collection, stream of values), it is some construction that contains multiple values, which does make sense in terms of loops and iteration.
In creative coding like games, graphics and audio you often just want to iterate x times to span or draw some stuff. It's only any other software where this makes less sense.
In godot there is no shorthand for enumerating iterators, so when you want to iterate over an array but also need the index, you can use this syntax with the array's size on the right. GDScript is concerned about being short and readable. If you read the docs this syntax is completely obvious and saves you from having to enclose the number in "range()".
It determines on the time complexity (which is faster to run). My CPP brain is telling me the second one will be faster to run. because it feels the *and* is being interpreted anyway as a && via a typedef (used in cpp to make an alias) or something else but i could be wrong here. their will be a short delay but nothing recognizable unless you get to heavy demanding games.
Also its very bad design to have magic numbers in your code (i.e. x), its fine if its just an example. their must be descriptors.
Comments as well, is more needed here. If it needs parameters to work you state the parameters needed to work otherwise explain what the function does. If you can't explain it, you don't understand what your doing.
Python person here: I had no idea "i in 100" was a thing. For the B version of it, I would prefer "for i in range(100)".
that syntax is bonkers. i would be confused if i saw that in the wild.
I don't mind "in 100". People are saying it's cursed but I'm just glancing over the docs now and `for in 2.2:` which is apparently the same as `for in range(ceil(2.2)):` seems way more cursed imo. edit: Turns out it feels cursed but is actually right: `for i in ceil(2.2):` becomes: `for i in 3: # prints "0, 1, 2"`
Actually in my head it makes sense that would be an implicit floor(). If I don’t have 3 then I shouldn’t be able to do that extra iteration.
Ahh! It does behave that way. The doc needs to be updated. 📗
Oh that’s good to know. Although I guess I would probably never use it like this, sounds a bit too magical!
Alright, so I actually opened an issue over the doc and I was wrong. We were both correct in assuming that "2" should be the last value. "ceil(2.2)" pushes up to "3" and therefore will print "0, 1, 2" which is actually correct. Seems odd at first! But it \*is\* correct. edit for clarity: `for i in ceil(2.2):` becomes: `for i in 3: # prints "0, 1, 2"`
mm, indeed.
It drives me crazy, because you actually _should_ use the ridiculous syntax. `range(100)`, unlike in Python, actually constructs the full 100-element array in memory and then iterates it, whereas just throwing the number in the `for..in` clause iterates without allocating any extra memory. This can be significant from a performance standpoint if your loop counter is large.
Python 3 doesn't construct the full 100-element array for range(100), either. Are you sure that Godot does?
Yeah, Python does it right and has a nice abstract "iterable" interface. But you can try it yourself. I'm running Godot v4.2.1 right now and `print(range(100))` prints out a massive array.
That just means that it converts to a string that way and not that there is an array in memory.
That's a shame. Good to know. Thanks!
Funny thing is, Godot actually has a fully-working iterable interface. So you _can_ write a proper `range` class by defining methods called `_iter_init`, `_iter_next`, and `_iter_get`. But as far as I can tell, this capability is completely undocumented. I only know about it from poking around in the source code.
Still, for what it is, GDScript does an impressive job. I can't fault it for not being as well-designed as Python, given the size of the community.
This is not true, it does not create an array. Both syntaxes are equivalent. Used to be the case, but haven’t been for a long time.
Are you sure of this? How do you know that "i in 100" does not create an array as well?
Bullshit. range inside a `for in` statement is optimized away. It does not allocate an array. It literally takes a few seconds to test this yourself. You gain nothing by spreading misinformation. Why would you do that? Go type in this: for i in range(2_000_000_000): break If range would allocate an array, the engine should crash because it's trying to allocate a huge array (60+ GB due to the size of a Variant). Even if it could, it should be blocking for a long time to do that. Well, does it? Or go ahead and print the memory usage inside the loop. It barely increases compared to outside the loop.
This!
So much this!
I like AABB
Same, AABB makes more sense and reads nicer.
AABB is fast to calculate but fairly limited for complex shapes. Wait, are we still talking about physics?
I only understood you thanks to Minecraft
I only understood him thanks to modding old niche game
What old niche game?
Yeah, but then we add some smaller ones, all over the complex shape. If calculus has taught me anything, it's that you can fix anything with enough small pieces.
Hehehe
Ah, the ABBA tribute act
Hehe
That's the most like actual python syntax which is maybe why we like it (except the last one which can be either A or B in Python)
Axis-aligned bouncing box
I agree but it depends a bit on keyboard layout, on some layouts the & and pipe are very hard key combinations, pipe is not even labeled.
I like ABAB, because AABB is a fairly basic rhyme scheme, while ABAB allows the lines to interweave more expressively in the time they are allowed to unfold, before being shoehorned back into the confines of the rhyme.
for x in 100 is cursed
I like it when iterating over arrays when I need the index. for i in a.size():
Same
Wait does that really iterate from 0 to 99? That is very bad syntax design..
Why is it bad design? It seems unambiguous and in line with Python’s syntax philosophy (emphasis on philosophy, not actual Python syntax), but maybe I’m mistaken or missing something. I don’t know much about designing languages.
Python syntax does not support that, and usually when you write **in** keyword, it usually implies in some **container/collection** that stores multiple values that you can iterate on. So when you write that you iterating something **for/while** usually it continues with some collection that you are iterating over, and not some number, which from usage and from any other perspective that you can think of, it does not make sense. when you specify **range(),** it's generator, it's like stream of values, or a collection that you iterate over, but do not store the whole thing in memory, still it is some stream of items that you will iterate over, overtime.
Yes, I know in Python the \`in\` operator takes an item as its first operand and a sequence as its second operand and checks if the item is in the sequence. In GDScript the \`in\` operator can also optionally take an integer as the second operand and create the implied sequence of numbers. It's more concise, it's unambiguous, and I think it's completely clear what it means. I would be interested to hear why the Godot developers made the choice and whether they would do the same designing Python or if they think its specifically useful for GDScript. Edit: Oops I started talking about the \`in\` operator but we're talking about the for statement which is different. Sorry I just woke up. But I think my point remains the same: replacing a sequence with an integer that implies a sequence doesn't make the statement less clear.
I know how it works in Godot, but it breaks consistency compared to any other language that supports loops, it's very ambiguous, since loops are for iterating some values, and not iterating over integers. What are you iterating over in integer? The bits of the integer? Completely ambiguous.
Oh iterating over the bits is a good example of the ambiguity. I wasn't seeing how someone might confuse it, but that's a good point.
As a freshy programmer, the "for i in 100" clicked and made sense to me, so its possible it's an ugly cursed line of code, that just makes it easier for noobs to get through a common pitfall. I do understand the ambiguity of it tho, and I would avoid it if I knew better. That being said, I wonder if I unintentionally have similar lines in my projects, due to how intuitive it would feel (as a beginner) to write it out that way, and it just so happens to work so I wouldn't necessarily know it was the "wrong" way to approach.
I know that it is targeted towards beginners. I know that beginners prefer shorter code, but there is a limit to sacrifice ***correctness/logic** over **code elegance**. As I mentioned in other comments, we already saw in Javascript that when you allow a lot of such hacky/elegant blocks of code, if you don't know what you are doing, it can become quickly big mess of code and impossible to debug. I don't claim that this feature would necessarily produce that, but multiple such features, it would create a ton of bad practices. Also, it can cause overlooked bugs.
It's targeted towards anyone who written a loop that runs from 0 to N - 1. Javascript is not elegant at all. This loop shorthand has nothing in common with the bad parts of JS. JS has no such shorthand and its issues stem from the dynamic nature, truthyness and nulls. Stop being condescending.
You should stop misunderstanding and misinterpreting what I'm saying.
It’d give me red flags for the entire language if they had syntax solely for iterating over the *bits* of a number, I’ve never heard of any syntax that does that, or what the justification would be for having syntax for such an esoteric use case. Are there any examples of languages that provide syntax for that already?
That was not the point.
Well you're saying it's completely ambiguous with only one suggestion for an alternative interpretation that u/Potterrrrrrrr is explaining doesn't really make sense.
I'm not saying that it is ambiguous only because it can be interpreted as "iterating of bits of the integer", it is because it can introduce bugs, bad practices for beginners, inconsistency with other languages, also someone might think it is for iterating (1, 100) or (0, 100) including 100, it loses the purpose of the syntax. I already have seen beginners make trivial mistakes even with Python syntax, let alone this monstrosity. It sacrifices clarity for elegance even tough most people can deduce why it is used, with scale it can quickly introduce overlooked bugs.
I know, your point was that it was ambiguous but ambiguous with what? Your example was iterating over bits which you’d never do and if you did you wouldn’t reasonably expect the language to have syntax for that. Can you think of an example that is valid that would actually make this syntax ambiguous? Of all the syntax to argue against, I’d never have thought that ‘for i in some_integer’ would be the example that’s contended. The only ambiguous part to me is what the initial value is, which quickly becomes unambiguous when you’ve written more than a handful of for/range loops and realise 90% of them start at 0. Genuinely just curious on your thoughts, I think this syntax is a nice, readable way to cut down on boring boilerplate.
Personally, I don't like odd edge-case/shorthand syntax like this in languages just because it's one extra thing to keep track of, and it doesn't have as much universal application. `range(0, 100)` can be used unambiguously throughout your code anytime you need a range of values. As long as you know what the range function does you can easily understand the logic wherever it's used. `for i in 100` on the other hand is only really useful in loops. It's probably not really allowed anywhere else, and if it is allowed it's not very readable (`if i in 100` sounds even more cursed because ranges aren't quite as implicit as for loops). So you likely won't use this syntax too often, and in 6 months or a year when you revisit your code, you'll probably have to remind yourself that it's the same as `for i in range(0, 100)` anyways. At that point, you may as well cut out the middleman and use the more explicit syntax
That makes sense. I use `for i in range(100)`, and I don't think I'll switch after learning this syntax. But I also feel like when all of us saw `for i in 100` we knew exactly what it meant, and the Godot team seemed to think it was a good idea so I'm trying to give it the benefit of the doubt. But as another comment pointed out, someone might think it's iterating through the bit sequence of the number rather than a range, and I get why people don't like it.
>someone might think it's iterating through the bit sequence Nobody would think that given GDScript is a high level scripting lang, and even if it wasn't, that idea is nothing more than a sweaty attempt at trying to come up with some possible misinterpretation, it's fine as long as it's a joke.
Good point. Looking over these threads it seems like that johny james fellow who made the comment about bit sequence is a bit of a pedantic fool. And your comments overall have affirmed my initial perspective that ‘for i in n’ is not bad syntax design.
It makes sense for anything that wants zero-based indexes. What is surprising to me is I can't find a way to make the last number be included
for x in 100 + 1
That works, it is just a wonky logical work around. I wonder if that gets optimized away or if it requires an addition step.
It's a bit cursed when it's just a straight into, but it's kinda nice when you need to loop based on a variable. It's less verbose than using a full `range()`
AABA, am I weird?
No, AABA is the only one
Same 🙏
Naw but as someone that lightly uses another language that uses ** to represent something else, I prefer the pow()
this, but `range(100)`
AABB. Yes I am used to Python, how did you know?
For me C++ is my primary language (yes, I know. Kill me now), and I still prefer AABB haha
Nah, all languages are beautiful!
True that. Although saying it's my primary language would be a lie. Since last august I have been primarily working with sql, qlik and a little python. I guess you could say C++ is the program I learned first
Python also has the ** operator. I prefer it because it's closer to mathematical notation.
I am aware of that and I would use it for integers, but for floats I prefer the pow function as floats only approximate the literals. Though, last time I mistyped it and ended up with 64 instead of 2^32 that took me a while to fix, so I personally find pow notation more robust to mistakes.
Fair enough. I admit I've made that same typo before.
Same!
I'm an ABBA person myself.
![gif](giphy|7vARoDgcIknS5wBQq6)
bbbb, but i come from the jvm world
AAAA master race. I spent too much time with C++ and Java. Gdscript feels so refreshing because you can write short readable expressions that almost read like a concise English sentence. I'm not giving that way!
I feel that. I was using C# a lot with Unity but started using Python for other projects. Every day I like Python more. Going into Godot I thought I’d use C# but I learned GDScript on a whim and it’s so nice.
but but bro you're gonna forget the syntax of the language you're using if you're away for a month or two! just keep using the verbose C-family style! /s
BABB
i in 100 works?
BAAB B, because it shouldn’t look the same as a for loop. A, because it is easier to read and debug. A, because I would use range to show I am using an unusual range. B, but only because it is less prone to typing errors.
This answer is even more correct because I actually 100% mistook it for a \`for\` loop until I read your comment.
I’m learning Zig and I have to say, I really like spelled out binary logical operators.
This. Only correct one.
The only part I don't like of A is \*\*. And I'd probably be fine with it if I used it more often. Maybe for i in range(0,100) explicitly gives me start and end points, while i in 100 seems very... undefined.
ABBB for me
*I would prefer if you put parentheses around this and/or statement so that we know what it actually does*
Came to the comments to say this lol. I have seen bugs in production C++ code because of this. It is at least consistent that "and" is "higher priority" than "or" but I find relying on that very unclear. While looking up the GDScript operator precedence I was surprised to find that the docs recommend "and", "or", and "not" over "&&", "||", and "!" which I personally don't like ESPECIALLY because they don't offer an alternative to "!=" so I don't see why they would discourage "!".
Clearly, you should write `not(a == b)` /s Personally I've come around to `or` and `and`, but `not` is still very odd... especially the cursed `if a not in b` syntax for `!b.has(a)`.
I actually debated between both of these in my head a lot, I think my actual conclusion is that both of them are sufficiently readable/clear and I wouldn't have an issue with either option. That being said, just for fun I'll give my answer for each one: * \#1: A. I was strongly leaning towards B, but if I were to set one as the "standard" across my codebase I'd prefer A specifically for "not" cases. "x not in []" is much cleaner than "![].has(x)" and IMO "in" is just as clear of a keyword as "has" anyways * \#2: B. But this one is so close that I actually don't mind either. I just like B slightly more because it's more natural to me based on my previous languages I've worked in * \#3: B. Your future self will thank your past self for explicitly stating ranges lol * \#4: B. Similar idea to #3. When you inevitably take a break from your project and come back to it 6 months later rusty as hell on GDScript, you'll probably prefer the immediate clarity of pow(x, y) over x ** y
one thing i do like about `x ** y` is it reads a little clearer to me what the base and exponent is. not sure if that's enough to overcome the advantage you mention, but it's something.
knowing that gdscript doesn't have generators both versions of the third option would give me pause, because id be afraid it's going to allocate an array. does anyone know if either is special cased to not do that in for loops?
`range()` returns an array only if used outside of for loops. When used in a for loop's `in` statement, it doesn't allocate an array, it's converted to a boomer loop under the hood. `in range(0, n)` is still ugly though.
well that's rather unintuitive... >in range(0, n) is still ugly though i don't think it's particularly bad, though i would want it written `in range(n)` when the beginning is zero. for me the ugly part is that iterating over ranges beginning at 0 has a special syntax that doesn't conceptually relate to the way you do other kinds of ranges. generally im of the opinion that if you're going to do a special range syntax for integers it should naturally extend to beginning/end and ideally also stride. otherwise it's just pointlessly inconsistent.
`for i in n` runs faster
Do you have a source? According to Godot's documentation, using `for i in n` is "similar" to `for i in range(n)` https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html
you may be right, but "similar" could really mean anything in this context.
Yes, the documentation I found doesn't contradict what they said, nor does it affirm it. That's why I want to know their source. Edit: also I noticed you said in another comment that the shorter syntax probably bypasses array allocation--and it does, but so does using the range function according to the documentation I linked.
Nope, `for i in n` is literally the same as `for i in range(n)`. It gets compiled to the same bytecode.
makes sense. it probably bypasses the array allocation and does a forward iterator type thing internally.
1:B. Having the keyword `in` have different meaning in `for` vs `if` can easily be confusing. Using "has" makes it clear that this is a function on an array. 2: A. Since the keywords `and` and `or` exist, they might as well be used. They are a bit morereadable than `&&` and `||`. 3: B. I think A was just added to Godot for performance reasons, but I think this doesn't really matter much in Godot 4. Although it should be `range(100)`. 4: B. Unless you are using powers a lot, then having an extra operator just for this is unnecesary.
I am person A all the way
AAA if you aim to make AAA games. The last one, let it be.
I didn't even know B was possible and was suffering through A. I'm a .Net developer so B plz
Isn't readibility meant to provide clarity? That being said, IMO, the clarity (right) one is more readable and clear than the left. (Except the Boolean operators, I prefer the left)
I much prefer lexical over double-operators.
BBBB
BBAB as my primary language for last 15 years is JavaScript
Ofcourse AABB !
CCCC and C as in C#
BBBA for me
The ‘or’ statement can be simplified btw. Not sure if real code or just an example but if x is 0 then it’s never 1. Checking if it’s not 1 is unnecessary.
But looking at the function names it’s probably just an example, in that case, it doesn’t matter! Haha.
BBAB. I'd use range only if I needed to start at a higher number or use a different step than 1.
I like func a but I’m a noob so it just reads easier for me.
I would do a combination of the two
Which do you prefer? Whatever makes the code readable not only to myself 6 months from now but also to others. Generally speaking, unless you’re targeting a platform where you need to be concerned about brevity, I find it is always better to be more verbose as it makes the code more understandable. So, it comes down to what makes the most sense to you from a legibility perspective.
AABB for me
Didnt know A1 was possible In gdscript i think A2 makes the flow of coding better I use B3 if the start value of the range is not zero, A1 otherwise And I only remember using pow, so B4
`AABA`
AABA for me
only B
AABA Actually who am I kidding BAAA looks cooler.
spaces 🤭 but seriously, ABBA. I prefer named booleans when writing conditions so && / || reads a little better and I've been programming for 13 years and I'm just used to it. and the range thing only works for a range that starts at 0 I'm guessing, so if you use the shorthand, it will be inconsistent with other ranges. that being said, I think I'd defer to the group I was working with. it's not that important to me compared to aiming for a cohesive codebase
AABA Basically how I would do it in Python
AABA this loop syntax scares me
AAAB...
BAAB personally
the first one. Bread before butter.
I mean i would prefer full on C syntax, but right I guess?
The funny thing is that BAAB is what I know is the better choice (though range is suitable too), but there is something I always find charming about line 2 of B. Maybe it is the C++ apologist in me. Also, catch me doing \*\* all the time anyways.
I use Elixir in my day job and it reads exactly like A, so I write that on accident. Helps so much that I forget I’m switching between languages and will either leave off “var” in Godot or write “var” at my job
I’m a func B truther
AABA Surprised the "static-type-only" demanders aren't upset that you haven't typecast x and i
B my C/C++ brain loves how clear it is
Agreed, any of the A syntax is making my brain melt.
A
\`if x in array\`
none. but statically type loops on A then we're good.
I do all of these inconsistently... I need to fix that
I like A better in all of them
I like right
Only going for A, they are more easy for me
BABA opinion B1. This is more human readable to me. We’re are checking “does the list have the element x” instead of “is the element x in the list of” A1. words over characters every day, every time. B2. Depending on whether we’re dealing with array of integers or a n array of object, I’ll switch between either A2. This notation is far more common
For me, ABBB. It's more intuitive coming from C++
I like BABB
What's the difference between improve readability versus improves clarity? That aside, A should run faster as it is using built-in operators so I would prefer A.
BAAA, based on what I use in my projects, all of them are fine though, I would use whatever necessary to get the job done
AAAB and that's only because I didn't know the syntax. Honestly they're both legible I find myself writing it both ways.
AABA
other than for i in 100 (which I really don't like), all the other parts, I prefer A, but probably because I like Python.
Got to represent Sweden where I can: ABBA
BBAX 1. B, because this could be defined as a variable somewhere else, and I prefer chaining functions, so ".has(...)" would be my intuitive approach 2. B I come from C++ and other langs, that used the operators, instead of keywords. It's just a preference tho 3. A honestly I havent seen this syntax anywhere else, but this is way more confortable to write in most situations, where you just go from 0..n, and it can also be a variable, or a .size() for expl 4. Depends on situation. I also prefer n*n over n**2 or pow(n, 2). I'd say I would use ** when raising to an integer constant, but pow(a, b) when using a variable as a power, or a float Reading through the other comments, this seems unusual, but I prefer it this way :P
AAAA. Aaaaaaaaaa!
I like a mix of the two honestly. I always prefer keywords to be complete real words, easier for my dyslexic ass to quickly see things and parse information. The less symbols the better for me.
Right, I like the pipes and ampersands 1000 times more and and and or
AA(b and a?)A For the third one if i use a fixed number i use range but when i use a variable or a method i dont like to wrap that in range.
AABA, is the most concise and readable imo.
and + or having syntax highlighting is more clarity than && + || without highlight for me. Everything else aren't different enough to be that big of a deal imo.
BAAB The first one in B has a special feature you learn in the industry: built-in null check. A constant is never null, whereas x can be.
Either or, as long as I understand it :p
For consistency's sake, I often fall back to official docs on these matters. Godot way is fast to write and looks less cluttered, but the other way is more standard to general non-Godot conventions. Everyone makes their own choices, I just try to be consistent per project.
B
Honestly, I just use whatever as long my project is done
Have good units tests and I won't mind either ways.
What font is that?
I'd prefer A. It's as unambiguous as B but more human readable (especially the second case). But I don't really care for the last two tbh.
I'm a BBAB but probably a rarity.
A
B, because that's how I was taught in Java and C++.
BBBA for me, with caveats. I'm wondering if `Array.has()` is less performant since it adds a method call to the stack and `in`... *might* not? I also am not entirely decided on whether I prefer `not`, `and`, `or` to `!`, `&&`, `||`.
ABBB no doubt
AAAA but *please* use parentheses for statements like #2 regardless of A or B.
Wait no other BBAA'ers in the house?
I guess I'm A either B either. The only one that really bothers me is "for i in 100", and even that I could get used to.
Respectively: in, and+or, in range(), **
A is more relaxing. If I need boring code, I have that at work. That for i in 100 looks weird though.
All to the B
B because it's more organized
X in [] but in i in range() and the explicit words rather than all of || and &&
Whichever makes the programmer finish their job faster.
ABBA
I, too, enjoy how elegantly terse that is, despite losing some inherent readability.
Neither, I love being pointlessly contrarian 👍 ``` func c(): if self["x"] in range(3): pass if is_zero_approx(get("x")) and not is_equal_approx(self.get("x"), 1) or is_equal_approx($".".x, 2): pass for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]: pass get_parent().find_child(name, false, false).x ** 1.5 * pow($"..".get_children().filter(func(child): return child == self)[0].x, 2) ```
the 'i in 100' and 'i in range (0,100)' are two completely different statements to any logical thinking person.
For the second item, you shouldn't chain comparators like that. Instead, either make a function that takes the arguments as inputs, and within the function do it in simple statements, or simply do it before this code and make the result what you test. A good rule of thumb; ONE is always fine (x > y), TWO is OK, as long as it's pretty simple and you can clarify with parentheses if needed (X > y > z) or ( (x > y) && z ), but if it's more than that, break it up: ``` a = x > y b = w == z c = x != 42 && y != 24 check == a && b && c ```
From my tests, `range` is significantly slower (like, over twice as slow), as it has to allocate an array to be used. This may also worsen memory fragmentation over time if used constantly. Always prefer `for i in 100:` where possible. Furthermore, using `and` and `or` just makes more sense. It helps distinguish comparison operators from the very similar-looking bitwise operators.
I want to make a comment about the 3rd case. It's an odd one because while I would always use A, I would never write it that way and I'm sure a ton of people aren't realizing that they use A more than B. It comes down to magic numbers, numbers where no meaning can be immediately gauged from them, and how giving meaning to them makes things more readable. While many would not think this looks normal: ``` for i in 100: ``` I believe there are many out there who might do something like this to get indices: ``` for i in array.size(): ``` And both are the same, one just has their magic number being given meaning. And if my range has a non-zero starting point, I'd find it more convenient to add an offset than to state the range still: ``` for i in NUM_OF_ALPHABETS: var char = i + CHAR_OFFSET ``` Though, I can never be sure of other's opinions and would like to open the question to those who have said that B is what they'd prefer to use. Do you still use B more often, or has my comment made you rethink your decision?
This from UX is very bad and it breaks consistency with any single programming language. When you are using loops (for, while) you are usually iterating over something (collection, stream of values), it is some construction that contains multiple values, which does make sense in terms of loops and iteration. But when you state single number and say **x in SOME\_NUMBER,** it really makes zero sense. What's inside **SOME\_NUMBER,** it can be confused that you are iterating over the bits of the number or something else. It's absolutely ambiguous.
Every language has its own rules and caveats that you can choose to learn. While it may not make sense in another language, it is an [explicitly expressed way to use the for loop in GDScript](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html#for). To say it's absolutely ambiguous is to ignore the documentation which also point out these things like the maximum and minimum values of `int`s or the fact that floating point numbers have blind spots in their representations. While it's understandable that someone can say, `int`s should be as big as we need them to be, or `float`s should be able to accurately represent every number within their range, that's just not the idyllic programming language we have. But, *you* should use what you or your team believe to be is the clearest way to convey your code. Ultimately, consistency is the key.
Godot developers allowing such functionality does not make something unambiguous. I know it's in the docs, I know that it replaces range, but I'm simply saying the design decision that devs made was poor and contradictory to any other programming language. Also, it breaks the concept of **for** loops, it is about iterating over some values, and with that syntax, you are iterating over what? An integer? How can you iterate over integer? It's one thing to allow it. It's another to decide to use it. It's similar to Javascript and all its monstrosities that it delivers. It invites bad practices and even more useless abstractions.
>This from UX is very bad and it breaks consistency with any single programming language. Not really and no, many programming languages have no for loops to begin with, and even if every single language didn't contain this syntax, it would not be a valid reason not to have something. There is a reason why people create new languages and it's not to have the exact same thing as something else. >When you are using loops (for, while) you are usually iterating over something (collection, stream of values), it is some construction that contains multiple values, which does make sense in terms of loops and iteration. In creative coding like games, graphics and audio you often just want to iterate x times to span or draw some stuff. It's only any other software where this makes less sense. In godot there is no shorthand for enumerating iterators, so when you want to iterate over an array but also need the index, you can use this syntax with the array's size on the right. GDScript is concerned about being short and readable. If you read the docs this syntax is completely obvious and saves you from having to enclose the number in "range()".
It determines on the time complexity (which is faster to run). My CPP brain is telling me the second one will be faster to run. because it feels the *and* is being interpreted anyway as a && via a typedef (used in cpp to make an alias) or something else but i could be wrong here. their will be a short delay but nothing recognizable unless you get to heavy demanding games. Also its very bad design to have magic numbers in your code (i.e. x), its fine if its just an example. their must be descriptors. Comments as well, is more needed here. If it needs parameters to work you state the parameters needed to work otherwise explain what the function does. If you can't explain it, you don't understand what your doing.