As far as I understood, the use
keyword disposes the bound IDisposable
as soon it is out of scope, so considering this recursive function:
let rec AsyncAcceptMessages(client : WebSocket) =
async {
let! message = client.AsyncReadMessage
use reader = new StreamReader(message)
let s = reader.ReadToEnd()
printf "%s" <| s
do! AsyncAcceptMessages client
}
Let's pretend that the compiler does not find a way of using tail recursion, would that StreamReader
be disposed after each recursion?
UPDATE
Tomas response show me a way of fixing it when you actually expect something back, but what if you are expecting nothing? like in this example with the StreamWriter
:
let rec AsyncAcceptMessages(client : WebSocket) =
async {
let! message = client.AsyncReadMessage
if(not(isNull message)) then
let s =
use reader = new StreamReader(message)
reader.ReadToEnd()
use writer = new StreamWriter(client.CreateMessageWriter(WebSocketMessageType.Text), Encoding.UTF8)
writer.Write s
printf "%s" <| s
do! AsyncAcceptMessages client
}
As you're saying, the
StreamReader
would only be disposed of after the execution returns from the recursive call (i.e. never).There is another issue, which is that
do!
is not treated as a tail-recursive call, so if you want to create an infinite tail-recursive loop, you need to usereturn!
(otherwise your code will be leaking memory).In this case, you can fix it easily using, because you're not doing any asynchronous operations with the
StreamReader
, so you can just create an ordinary local scope:If you wanted to call e.g.
AsyncReadToEnd
, then you could do something like: