-
Notifications
You must be signed in to change notification settings - Fork 822
Using for-loops with the ".." operator produces suboptimal code #9548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
It creates a sequence. It's twice as fast if you use the I believe there's a feature underway that allows for such optimizations, though, which would blur the performance differences more. Ultimately, both your examples should compile into the IL code for a |
That's interesting. For sure, only a few days ago, I noticed the opposite, and I was considering filing a bug for it. I'll try to find that back, as that may suggest that it depends on the situation. EDIT @teo-tsirpanis: the only thing I could find back was proof of the inverse, notes in my code saying that Of course, differences do exist if the argument after Bottom line: as written you are absolutely right with your observation :) |
Hmm, it can be subtle. Consider this: > let f y x = for _=0 to y do for i in x do String.length i |> ignore;;
val f : y:int -> x:seq<string> -> unit
> let g y (x: array<_>) = for _=0 to y do for i in x do String.length i |> ignore;;
val g : y:int -> x:string array -> unit Now, when you call If, instead, you were to do a type-test before entering the loop and use two paths for sequence and arrays, you get the original perf of There's something to be said to optimize this in the compiler too (though not directly your original request, sorry for digressing). > let values = [|"a";"a";"a";"a";"a";"a";"a";"a";"a"|];;
> f 10_000_000 values;;
Real: 00:00:00.846, CPU: 00:00:00.842, GC gen0: 51, gen1: 1, gen2: 0
> g 10_000_000 values;;
Real: 00:00:00.113, CPU: 00:00:00.124, GC gen0: 0, gen1: 0, gen2: 0 |
Note that the optimization does not happen for other numeric types: https://sharplab.io/#v2:DYLgZgzgPmD2BOACAHoglgO0QBgDIDp8BGbPRAE1kQAd5MAXMLAIgAsBTYYWZoA= Though it is admittedly not as straightforward, since you can't index into an array unless it's an int. |
These two paths would require the entire loop body code to be duplicated. I'm not sure whether it's worth it. After all, the developer is fully aware of the performance implications the Something better we could do is to perform type tests on
@cartermp your snippet should be optimized into |
I'd only be interested in the following cases, which I think make sense:
People should not be punished when using an array in a function that accepts a sequence (when we can help it). |
Uh oh!
There was an error while loading. Please reload this page.
Consider the following snippet:
It produces a nice, C#esque for-loop. Now consider this one:
It creates a sequence and then enumerates it. And it also has a consecutive pair of
ldnull; pop;
twice, as well as a needlessunit
local.Producing a
for (int i = 0; i < 15; i += 2)
in the second case would have been much more efficient. We could even generalize it to arbitrary types with an addition operator, not just ints. Furthermore, in the first example, replacing the loop withfor x in 0.0 .. 15.0
creates a sequence too.In addition, using like
for x in [0 .. 15]
does correctly produce a list, but the compiler should warn to better remove the brackets when using a ranged list literal in a loop.The text was updated successfully, but these errors were encountered: