What is the effect of "if false then ()" in the Computer Language Benchmarks Game's F# Threadring entry?
f#
Solution
If the computation expression contains `if false then ()` then the asynchronous workflow gets translated a bit differently. With the line, it uses `async.Combine`. Slightly simplified code looks like:
async.Delay(fun () ->
value = cells.[i]
async.Combine
( async.Return(if false then ())
async.Delay(fun () ->
match value with (...) ) ))
The translation inserts `Combine` because the (potentially) asynchronous computation done by `if` loop needs to be combined with the following code. Now, if you delete `if` you get something like:
async.Delay(fun () ->
value = cells.[i]
match value with (...) ) ))
The difference is that now a lot more work is done immediately in the function passed to `Delay`.
EDIT: I thought this caused a difference because the code uses `Async.StartImmediate` instead of `Async.Start`, but that does not seem to be the case. In fact, I do not understand why the code uses asynchronous workflows at all...
EDIT II.: I'm not entirely sure about Mono, but it definitely does replicate in the F# interactive - there, the version with `Combine` is about 4 times slower (which is what I'd expect, because of the function allocation overhead).
Problem
The Computer Language Benchmarks Game's F# entry for Threadring contains a seemingly useless line: `if false then ()`. When I comment out this line, the program runs much faster (~2s vs ~55s for an input of 50000000) and produces the same result. How does this work? Why is this line there? What exactly is the compiler doing with what appears to be a no-op? The code: ``` let ringLength = 503 let cells = Array.zeroCreate ringLength let threads = Array.zeroCreate ringLength let answer = ref -1 let createWorker i = let next = (i+1)%ringLength async { let value = cells.[i] if false then () match value with | 0 -> answer := i+1 | _ -> cells.[next] <- value - 1 return! threads.[next] } [<EntryPoint>] let main args = cells.[0] <- if args.Length>0 then int args.[0] else 50000000 for i in 0..ringLength-1 do threads.[i]<-createWorker i let result = Async.StartImmediate(threads.[0]) printfn "%d" !answer 0 ```