5

I have this code that downloads a file and tells me in the console how big is the file:

use webClient = new WebClient()

let lockObj = new Object()
let mutable firstProgressEvent = true
let onProgress (progressEventArgs: DownloadProgressChangedEventArgs) =
    lock lockObj (fun _->
        if (firstProgressEvent) then
            let totalSizeInMB = progressEventArgs.TotalBytesToReceive / 1000000L
            Console.WriteLine ("Starting download of {0}MB...", totalSizeInMB)
        firstProgressEvent <- false
    )

webClient.DownloadProgressChanged.Subscribe onProgress |> ignore
let task = webClient.DownloadFileTaskAsync (uri, Path.GetFileName(uri.LocalPath))
task.Wait()

Is there a way to do the same, but using neither locking nor mutable vars?

knocte
  • 16,941
  • 11
  • 79
  • 125
  • 1
    I think you might want to use the lazy type here – John Palmer Jan 03 '17 at 08:52
  • how exactly John? – knocte Jan 03 '17 at 13:34
  • I don't think it can be done with lazy, as you would want call `.Force()` each time you handle the event, but you need to bake the first value into it, it doesn't work. You could look at using [the memoize pattern](https://blogs.msdn.microsoft.com/dsyme/2007/05/31/a-sample-of-the-memoization-pattern-in-f/), that way it will print one and each time the value changes (never). But this will be just as verbose as you already have, if not worse. – Stuart Jan 03 '17 at 17:33

1 Answers1

5

Here is one way using the Reactive Extensions:

open System.Net
open FSharp.Control

let webClient = new WebClient()
let disposable = 
  Observable.take 1 webClient.DownloadProgressChanged 
  |> Observable.subscribe (fun progress -> printfn "%A" (progress.TotalBytesToReceive))
Kevin
  • 2,281
  • 1
  • 14
  • 16
  • 2
    The [Observable](https://msdn.microsoft.com/visualfsharpdocs/conceptual/control.observable-module-%5bfsharp%5d) in the `FSharp.Control` namespace is built into F# without the `take` function. So to be clear, you need this NuGet package for this to work: [FSharp.Control.Reactive](https://www.nuget.org/packages/FSharp.Control.Reactive). – TheQuickBrownFox Jan 03 '17 at 10:29