I’m just curious about which is the most efficient way of doing this kind of node enumiration:
for i in something():
o=[var1,var2,var3,varN][i]
o.new()
o.do_something_based_on_number_of_loops()
add_child(o)
or
for i in something():
match i:
0:
o=var1
o.new()
o.do_something_based_on_number_of_loops()
add_child(o)
1:
o=var2
o.new()
o.do_something_based_on_number_of_loops()
add_child(o)
2:
o=var3
o.new()
o.do_something_based_on_number_of_loops()
add_child(o)
N-1:
o=varN
o.new()
o.do_something_based_on_number_of_loops()
add_child(o)
or
var items = [var1,var2,var3,varN]
for i in something():
o=items[i]
o.new()
o.do_something_based_on_number_of_loops()
add_child(o)
Or is there a more efficient way of doing it?
Edit: Sorry if that wasn't clear. Is it better to constantly get something from an "unstored list", store the list in a variable, or not use a list and use a match statement instead? Do they have any advantages/disadvantages that make them better in certain situations?
Rule number 2: stop dismissing performance questions just because of something some guy said decades ago. Performance matters, learning about performance matters, and answers like yours dont help anyone.
Did they ask if they should optimize, or did they ask which one generates more performant assembly? Which one of those questions did you answer?
Maybe they already measured and already knows this is a bottleneck. Maybe they are curious if match statements are a slow abstraction (e.g. in python, it's essentially a chain of if/else. In rust it's often compiled to an indexable table). Maybe the given example code is only partially representative of the actual code this is being applied to.
It's so irritating to look up performance-related questions when this answer is at the top (and middle, and bottom) of every thread. I swear half the reason every piece of modern software runs like shit is because nobody bothered to learn how to optimize and now everyone just parrots that phrase instead of saying "i dont know".
There's tons of little "premature" optimizations that you can do that arent evil. Choosing the right data structure (how random is the access? Are you using keys? Does it need to be sorted?). Estimating time complexity and load size (e.g. "i'm parsing [11 million | 2] files, i should probably [keep time complexity in mind | ignore time complexity completely]"). Structuring loops in a way that's easy for compilers to auto-vectorize - usually it's not any harder to read what the loop is doing, so why not do it right away?
I did not dismiss it, I said measure the performance yourself.
Performance matters, learning about performance matters
Which is why I said you should measure performance. It's no use waffling about unmeasurable performance gains.
Did they ask if they should optimize, or did they ask which one generates more performant assembly?
To be pedantic, GDScript is an interpreted language, and does not generate bytecode or assembly. This means that the code performance is highly dependent on runtime conditions, and needs to be measured in the place where it's used.
Maybe they already measured and already knows this is a bottleneck.
If they already measured, then they would know which one is faster, because they measured it.
I swear half the reason every piece of modern software runs like shit is because nobody bothered to learn how to optimize
This is unrelated to what I said, which is "you should measure your performance to see what you need to optimize".
There’s tons of little “premature” optimizations that you can do that aren't evil.
And all of these optimizations are just as effective after you measure them to see if they're needed, and they're no longer premature.
Estimating time complexity and load size
Accurately estimating the performance impact of a design choice means the optimization is no longer premature. The rule-of-thumb is about using optimizations without taking appropriate time to their overall performance benefit. The particular question asked by the OP is very very unlikely to have any significant performance impact at all, unless it's in an extremely hot loop running millions of times per frame, at which point you should measure it to see which one is faster in your use case.
This is the most direct way of doing what you want. The first option might allocate a new array each iteration, which is unnecessary. The match statement is both a pain in the ass to write and less direct, which at best compiles to the same thing and at worst has you doing a bunch of totally unneeded comparisons.
If this 'i' variable you used isn't just an incrementing counter, use the last option. If it is though, it's an extra counter you don't actually need.
The performance difference here would be so small I doubt you could even observe it. So, you really shouldn't worry about this particular pattern. Compiler optimizations are more likely to trigger on simple, direct code, so writing it as directly as possible is probably the fastest option anyway.
Speaking generally, I'd prefer the first option as long as 'i' is actually an index or other valid key. I'm not sure what the overhead is in godot, but in general you should avoid conditional statements when you have a direct access method like a key or index.
For that for you presented later, it should be for i in items:, i then will point directly to the value in that position of the array.
o = i
What you are doing, or attempting to, isn't clear
At face value, none of those things are "apples to apples", the first thing is a matrix or Vector2. The second is simply a match, which is "a series of if/elif". Efficiency here comes mainly from the type of of the object being matched: bool is the fastest, int probably second, then float, then string. The third you're just running through the array. All different things, each useful for a different purpose and none directly equivalent to another, thus it's impossible to say which is the most efficient.
If speed is actually important then I would consider writing it in another language looking for someone else's implementation (personally). I try to focus on readability and doing the simplest implementation. I've been trying to use better function/variable names to explain what is happening at a glance instead of reading the whole thing. Have you considered using map for array iteration? I am hoping even if people don't know how this works the intended result is even more readable than an equivalent for loop:
I find that much harder to read than a for loop. You are making a helper function to only use it once, which is kind of confusing when it is totally unnecessary. Also, distinguishing between two groups only inside the setter line is weird. Applying the modification to one group, then the other, is more obvious. Considering the alternative isn't really longer, and only using basic loop syntax, I would just use the loop. If you really want to add the "set dots visibility" explanation into it, just use a comment, that's what they're for.
I literally just now misunderstood your code and had to change my comment to correct for it.
You looked at how it works and made comments about that (which I am thankful for and will enjoy replying to below). Can I first bring your attention to what is does instead of how it does it. Do you think that the names of the method function and helper function made it's intended result clear? Could the use of map be so unexpected as to be a distraction?
I shouldn't have included the node.visible = (expression) in the example, that was needlessly complex. It's just what was in front of me (I do however find it appealing because it reduces the number of lines but that is another discussion).
While for loops are a popular method taught to every programmer early on then a for loop is easier to understand step by step. I do find occasions where a for loop just looks better but I keep finding that I better understand what my code is actually doing when I try to write a loop using functional programming methods.
func _show_only_first_layer_dots():
for c in $Layers.get_children():
c.get_node("Dots").visible = false
$Layers.get_child(0).get_node("Dots").visible = true
Mines 10x more readable and I saved a line of code.
If you're working on the function then yes; everyone learns for loops fairly early on.
If you just need to know what it is intended to do then I would argue you didn't need to read anymore than the function name. If you do look further then I'd argue just the name of the helper function was easier to read than the whole for loop.