views:

113

answers:

3

Hi,

I have the code below which is basically calling a Domain Service in a SilverLight Application.

LoadOperation<tCity> loadOperation = _dataContext.Load(query,callBack, true);

Can you tell me which operation is done first?

Is the callBack method called before loadOperation variable is assigned or after it is assigned?

Thanks

+2  A: 

Assuming it's meant to be an asynchronous operation, it could happen either way, in theory. The asynchronous operation should occur in another thread, and if that finishes before Load returns, the callback could be called before the assignment completes.

In practice, I'd expect the async call to take much longer than whatever housekeeping Load does at the end of the method - but I also wouldn't put that assumption into the code. Unless there's explicit synchronization to ensure that the assignment occurs before the callback, I don't think it's a good idea to rely on it.

Even if at the moment the assignment always happens first, consider:

  • What happens if there's no network connection at the moment? The async call could fail very quickly.
  • What happens if some caching is added client-side? The call could succeed very quickly.
  • I don't know what kind of testing you're able to do against the RIA services, but sometimes you may want to be able to mock asynchronous calls by making them execute the callback on the same thread - which means the callback could happen in tests before the assignment. You could avoid this by forcing a genuinely asynchronous mock call, but handling threading in tests can get hairy; sometimes it's easiest just to make everything synchronous.

EDIT: I've been thinking about this more, and trying to work out the reasons behind my gut feeling that you shouldn't make this assumption, even though it's almost always going to be fine in reality.

Relying on the order of operations is against the spirit of asynchronicity.

You should (IMO) be setting something off, and be ready for it to come back at any time. That's how you should be thinking about it. Once you start down the slippery slope of "I'm sure I'll be able to just do a little bit of work before the response is returned" you end up in a world of uncertainty.

Jon Skeet
@HiTech: I agree that in reality it will happen before Load returns, but is that actually *guaranteed* - or is it just because the call takes a while in practice? In other words, are you saying there is synchronization to *ensure* that the callback doesn't occur before Load returns? I'll edit my answer.
Jon Skeet
@HiTech: But you're still saying it's just because it happens faster - not because of synchronization, right? So it's like having a race condition, but that race is a 100 mile race between a tortoise and a train? If that's the case, then the most appropriate approach is definitely a matter of opinion, but I think it's reasonable to code defensively for the reasons given in my edited answer.
Jon Skeet
+1 for Jon here. I agree that async call will take much longer but it is not **guaranteed** anyhow, and this **is** the point. Code that relies on assumptions like this can be a pain in the ass to change and maintain because assumptions are defined in mind, rather than in code. If you really are sure that method hasn't yet been called, and you want to rely on it, do an `Assert`. This will give a hint to anyone working with your code later what conditions your code relies on.
gaearon
@HiTech: Why would it perform any locking though? If you treat asynchronous calls as "it could happen any time" then you don't need any synchronization. I'm just saying that it seems foolish to encode an assumption that an asynchronous call will occur at a particular time, unless there's any *guarantee* that it won't. Note that looking in reflector will only show you the *current* implementation. Are there guarantees written in the docs? If not, make no assumptions.
Jon Skeet
@HiTech: Yeah, I think agreeing to disagree will be the best course of action. Personally I don't think that coding defensively against race conditions is inappropriate, but there we go.
Jon Skeet
@HiTech: Did you read the latest edit to my answer? That should explain my thinking a little bit more. If you're using asynchronous operations, you should think of them as being truly asynchronous, IMO.
Jon Skeet
@HiTech: Haven't you just answered it yourself? The callback should use the context, not the return value... so why should you need to write which *assumes* the assignment has taken place?
Jon Skeet
@HiTech: My answer is based on generic *asynchronous* practice - it's not C#-specific at all. If you make an asynchronous request, you should think of it as entirely separate from the thread that launched it, unless there is explicit synchronization (e.g. to make the callback occur in the dispatcher thread). If the OP wants to use the result of the assignment, that probably indicates that they're thinking about asynchronous calls in the wrong way. I think that's worth flagging, personally.
Jon Skeet
@HiTech: I'd say that I'm actually focusing on the *bigger* picture rather than the minutiae. As for whether your answer is correct: in practice, I believe so. In theory, no. You're still encouraging people to rely on a sequence which isn't guaranteed, and *shouldn't* be guaranteed, because of the asynchronous nature of the system. Will add a comment.
Jon Skeet
@HiTech: Please don't delete your comments - that's pointless, and just removes useful discourse for other people to read later on. (I don't buy the "saving bandwidth" argument at all.)
Jon Skeet
@HiTech: To be honest, that behaviour seems chlidish to me. It's perfectly easy for someone to read just the answers if they really wanted to. They're in a bigger font and everything. Given that there have been upvotes on some comments, clearly other people find the discussion interesting. Why do you want to prevent future readers from finding the same discussion interesting?
Jon Skeet
A: 

First, I would say write your callback without any assumptions. But aside from that I don't see how the callback could possibly occur before the assignment. The load operation would have to return immediately after the thread is spun.

Kirk
A: 

There are 3 possible answers to this very specific RIA Services question:

  1. It returns the assignment before the callback.
  2. It may be possible for the callback to occur before the assignment.
  3. You do not care.

Case 1: Based on a .Net Reflector investigation of the actual load method in question, it appears impossible for it to call the callback before the return occurs. (If anyone wants to argue that they are welcome to explain the intricacies of spinning up background threads).

Case 2: Proof that "the sky is falling" is possible would have to be shown in the reflected code. (If anyone wants to support this they are also welcome to explain the intricacies of spinning up background threads).

Case 3: In reality, the return value of a RIA Services load method is normally used to assign a lazy loading data source. It is not used by the callback. The callback is passed its own context, of the loaded data, as a parameter.

StackOverflow is all about practical code answers, so the only practical answer is option 3:

You do not care (as you do/should not use the assignment value from the callback).

Enough already