Why MailboxProcessor.TryScan is 'Msg -> Option<Async<'T>> -> Async<Option<'T>>? It would seem more natural to me for it to be 'Msg -> bool -> Async<Option<'Msg>>, with the semantics like Seq.tryFind, i. e. the first matching message returned. Looks like my intuitions about its paradigm are wrong.

Note that the Scan and TryScan functions invoke the function argument you give them an arbitrary number of times with a lock held for the entire time, preventing anyone else from posting to the agent. So you can easily deadlock an agent using these functions by trying to post to it from inside the function you pass to Scan or TryScan.

As a rule of thumb, avoid these functions and process incoming messages immediately. If you want to prioritize them, process them immediately and place them on agent-local message queues of your own.

By on 9/10/2010 6:55 PM ()

Hi,

this is because unlike tryFind - Scan and TryScan are used to PROCESS a subset of possible messages instead of finding them.

Normally you use the Scan-function as the only call in the "inner loop" of your messagebox.

I hope this helps.

By on 8/19/2010 10:01 PM ()

Normally you use the Scan-function as the only call in the "inner loop" of your messagebox.

That might be true about Scan, but less so about TryScan. What I have trouble understanding is this. I believe that the following 2 pieces of (somewhat pseudo) code are equivalent:

1
2
3
4
5
6
7
8
type Message = A of T1 | B of T2
let rec state1 = async {
   (* Processing only A's *)
   let! msg = inbox.TryScan (function (A _) as m -> Some (async.Return m) | _ -> None)
   match msg with
   | A x -> return! processA x
   | _ -> return! processNone ()
}


and (with the same definition of Message and semantics)

1
2
3
4
5
6
7
let rec state1 = async {
   let! res = inbox.TryScan (function (A x) -> Some (processA x) | _ -> None)

   match res with
   | Some r -> return! r
   | None -> return! processNone ()
}

Both of them look almost identical to me: the difference is only in the place where the processing of the A message is done. The following would rather look more aesthetically appealing

1
2
3
4
5
6
7
let rec state1 = async {
   let! msg = inbox.TryScan' (function A _ -> true | _ -> false)

   match msg with
   | A x -> return! processA x
   | _ -> return! processNone ()
}

The above, however, is not the implemented paradigm. I am trying to understand what's wrong with my reasoning, if you want: either the designer of MailboxProcessor would reject my argument from aesthetics, or I am missing something that's rationally important here.

By on 8/19/2010 10:43 PM ()

I think there is a fundamental difference here. The current TryScan signature seems to follow the more functional async paradigm where you pass in a function which would handle the message(whatever it is). The result is Async<'T>, the real stuff.

Using your signature seems to follow the more traditional imperative style of 'get me my message first, then I would dispatch it based on what I get'. The result is Async<'Msg>, the unprocessed stuff.

The current signature would facilitate composition as filtering and processing is done in one function.

Your signature relies on the dispatcher after the let! which seems to be more difficult to refactor and compose.

By on 8/20/2010 3:05 PM ()

I think there is a fundamental difference here. The current TryScan signature seems to follow the more functional async paradigm where you pass in a function which would handle the message(whatever it is). The result is Async<'T>, the real stuff.

Using your signature seems to follow the more traditional imperative style of 'get me my message first, then I would dispatch it based on what I get'. The result is Async<'Msg>, the unprocessed stuff.

The current signature would facilitate composition as filtering and processing is done in one function.

Your signature relies on the dispatcher after the let! which seems to be more difficult to refactor and compose.

I also think so.

_________________
watch movies online

By on 9/9/2010 2:20 AM ()

I think there is a fundamental difference here. The current TryScan signature seems to follow the more functional async paradigm where you pass in a function which would handle the message(whatever it is). The result is Async<'T>, the real stuff.

Using your signature seems to follow the more traditional imperative style of 'get me my message first, then I would dispatch it based on what I get'. The result is Async<'Msg>, the unprocessed stuff.

I agree there is a difference in styes, but the current implementation, as I understand it, forces you to apply both. The result is checked for None and that case is handled by the continuation, outside of the TryScan argument function. That's what makes it look somehat inconsistent to me.

By on 8/20/2010 10:38 PM ()

may be I misunderstand what you want. Why would I check for None outside TryScan ? None means nothing in the queue has been processed(I assume). And if you need to, it is the only case, more like an exception to me, if you want to handle it.

Your style however needs to be put all the match A _ | B _ | C _ ... after the TryScan and if you add a new message type, you need to change this as well as the function you pass to TryScan

By on 8/21/2010 9:59 AM ()

may be I misunderstand what you want. Why would I check for None outside TryScan ? None means nothing in the queue has been processed(I assume). And if you need to, it is the only case, more like an exception to me, if you want to handle it.

I'd say because I need the result of the computation as 'T (see the signature in the topic post), and I am getting a 'T option. Think of the pretty common state machine pattern of mutually recursive functions. When no message was fetched, I still need to "shift to a state," therefore, I need to match a returned None immediately. There is no other option as a match statement on the result of TryScan.

I understand that you say you recognize some other uses of MailboxProcessor with TryScan as most common -- just out of curiosity, what are they? Maybe I am just looking at it from one point out of many possible.

By on 8/22/2010 9:44 AM ()

In your case, may be the current TryScan signature doesn't fit what you want. Though even as it is now, you only has two cases at hand, None or Some('T) so it still matches largely what you want, treating the None as 'special case'.

I didn't mean that I see other usages of the current TryScan pattern as common, but its style is common in other area I have been recently working on. Like most of the Google javascript API(map, translate etc.) as well as Microsoft's auto generated WCF client side proxy both prefer this kind of CPS style where the return of the call(like TryScan) is unimportant(nil or a handle which has nothing to do with the actual process) as it is async and may be just queued waiting for execution. It would be the passed in continuation function that would decide what next(when the actual content is available). I do need to adjust my coding a bit to fit to this paradigm but have the feeling that we are going to see more and more of this form.

I think it boils down to async vs sync. You pattern expects meaningful return from the call, which is what we have used in the sync model for so long. In an async model however, the return from the call is in general meaningless as it is in a sense 'queued' and return immediately.

By on 8/22/2010 10:43 AM ()

Yes, I've also done this.. thanks for the help.

By on 9/14/2010 9:11 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper