BeginInvoke's last parameter: What's in a name?

I have been playing around with asynchronous programming lately and it bothers me that the last parameter to the begin invoke pattern doesn't have a name that everyone agrees on. The begin invoke pattern is the asynchronous calling pattern were the BeginXxxx(), such as Stream.BeginRead(), takes a set of parameters, a callback method, and some, well, thing, at the end that is carried along with the asynchronous operation that eventually finds it way into the IAsyncResult. The problem is what do we call that thing? In an informal survey of the methods in the BCL that implement this pattern I have found a wide variation. Here is a partial list in somewhat order of popularity,

  • object
  • stateObject
  • state
  • asyncState
  • extraData
  • data

There seems to be little agreement about what to call it. We could pick the most prevalent but the name object occurs the most often because every delegate gets a BeginInvoke() method created for it and in this automatically generated code the parameter is called object. We can't standardize on object because it is a reserved word in several languages so either it would be impossible to specify or awkward (i.e. @object in C#). What I would like is a name that we can all use and we can all agree on.

To name the thing, we first must understand why it it is there at all. It exists to hold some state on behalf of the caller. Having the state object makes programming against the begin invoke pattern easier in languages that do not have anonymous methods that capture local variables. Consider the following program (which intentionally ignores errors because it is only an example),

const string uriFormat = 
    "http://messenger.services.live.com/users/{0}@apps.messenger.live.com/presence";
const string responsePattern = 
    @"""statusText""\s*:\s*""(?<status>\w+).*""displayName""\s*:\s*""(?<name>\w+)""";

static void Main(string[] args) {
    var uri = string.Format(uriFormat, args[0]);
    var request = WebRequest.Create(uri);
    var result = request.BeginGetResponse(PresenceCallback, request);

    // Other interesting work....

    result.AsyncWaitHandle.WaitOne();
}

private static void PresenceCallback(IAsyncResult result) {
    var request = result.AsyncState as WebRequest;
    var response = request.EndGetResponse(result);
    var s = new StreamReader(response.GetResponseStream()).ReadToEnd();
    var search = new Regex(responsePattern);
    var match = search.Match(s);    
    if (match.Success)
        Console.WriteLine("{0} is {1}", 
           match.Groups["name"].Captures[0].Value, 
           match.Groups["status"].Captures[0].Value);
    else
        Console.WriteLine("Unexpected response");
}

This will get the online status of a Windows Live Messanger account given the live ID account number. For example, passing 1afa695addc07e5 as an argument to the above will tell whether or not I am online. In this case I am using last parameter of the BeginGetResponse() method to pass the request itself. This then is cast back to WebRequest in the PresenceCallback() method so I can call EndGetResponse() to retrieve the actual response. As far at the BeginGetResponse() call is concerned, this value is opaque. It ignores it completely and just supplies it blindly in the IAsyncResult. It makes no assumptions about the data at all, it is just something the caller just wants carried around. If I was using anonymous delegates in C# this would look a lot better as,

static void Main(string[] args) {
    var uri = string.Format(uriFormat, args[0]);
    var request = WebRequest.Create(uri);
    request.BeginGetResponse(result => {
        var response = request.EndGetResponse(result);
        var s = new StreamReader(response.GetResponseStream()).ReadToEnd();
        var search = new Regex(responsePattern);
        var match = search.Match(s);    
        if (match.Success)
            Console.WriteLine("{0} is {1}", 
               match.Groups["name"].Captures[0].Value, 
               match.Groups["status"].Captures[0].Value);
        else
            Console.WriteLine("Unexpected response");
        }   
    }, null);

    // Other interesting work....

    result.AsyncWaitHandle.WaitOne();
}

Here the request local variable request is captured automatically by the C# compiler and placed into a compiler generated class as a field. The compiler generated class also contains the code I supplied in the lambda as an instance method. When I refer to response in the lambda the reference is automatically translated into a field lookup in the generated class. Since request is already accessible in the lambda I don't need the last parameter to carry anything useful so I pass null.

Anonymous methods makes using callbacks much easier but since not all languages support anonymous methods or lambdas the BCL standardized on a method pattern for begin invoke that can easily be used by those languages. If the calling pattern did not have a caller state object then the work performed automatically by the C# compiler would have to be repeated manually by the programmer in these, then, second class languages. The .NET team did not want such languages to be second class citizen (especially since neither C# nor VB.NET supported anonymous methods initially) so they required the presence of the caller state object parameter.

Now we know why it is there, what to do we call it? I like state because the parameter represents state the caller want's to preserve. I don't like object because it is a common reserved word. I don't like stateObject because a symbol's type should not be repeated in the name, we already know it is an object by its type. asyncState is acceptable, especially since that is the name it is given by IAsyncResult, but it is a bit redundant, we already know, by context, it is asynchronous state. Plus we should avoid abbreviation, like "async", in symbol names (though it is very common, and asynchronous is very very long, so not that bad). data seems fine to me, it is a synonym to state, but it is overused. extraData I cannot, for the life of me, figure out. Extra for whom? Extra as opposed to what? Unfortunately, this is the name given to the parameter by IHttpAsyncHandler (see, I told you "async" was common).  Its name tells me nothing about what I should do with it. It is very unclear that this value should be mapped to AsyncState in IAsyncResult.

I propose we call it state, with an acceptable variation of asyncState.

Now, if changing a parameter name was not a breaking change...


Trivia:

  • The above uses the Live Services that you can find more about here.
  • The IM presence service returns JSON which I parse using a fancy looking Regex instance. I recommend that production code use DataContractJsonSerializer() instead.

06/16/2008 6:11 PM

I like asyncState, if only for the reason that IAsyncResult has the AsyncState property -- so the final resting spot for the value is (slightly) more clear.

But, I could live with state as well. :)

Aaron | http://www.wiredprairie.us | coderAT NOSPAMwiredprairie dot us

06/17/2008 6:06 AM

I don't like 'state' doesn't tell you whose state it is, is it something that belongs to the callback that I shouldn't fiddle with?

I wouldn't call it state either, as often as not I use it to pass a reference to an object that is not purely a state object.

I would call it 'userData'.

Marc

06/17/2008 6:10 PM

I didn't recommend userData or callerState or callerData or other probably more descriptive names because they are not currently in use. I wanted to recommend one that is currently used in the BCL.

Chuck Jazdzewski | www.removingalldoubt.com | chuckjAT NOSPAMmicrosoft dot com

07/14/2008 6:41 AM

I usually use context, or much more rarely userContext.

07/15/2008 6:27 AM

I agree Chuck "userData or callerState or callerData" are good names. But if you want to limit the possible names to the BCL list, then, the "less worse" is "data".
"extraData" doesn't say more than "data" (and if there's "extra" data, one will look around to find where are the "non extra" data...). So "data" is a good choice.
All names with "state" are too restrictive, data is more generic. And names using "object" are colliding with some language type name as you noted it.
Go for "data" so...

olivier | http://www.e-naxos.com/blog | odahanAT NOSPAMgmail dot com

07/15/2008 7:45 AM

asyncState seems fairly succinct to me. : )

Scott | mailto:cmdrbeavis at gmail otDay omKay | cmdrbeavis at gmail otDay omKay

07/15/2008 11:09 AM

If you're excluding non-BCL names, I think asyncState makes the most sense (matching the propery name). On the other hand, data or asyncData is the best non-BCL name.

Joshua Garvin | mailto:jkaldonAT NOSPAMgmail dot com | jkaldonAT NOSPAMgmail dot com

07/17/2008 12:44 AM

I would use AsyncData or ExtraData.
Much more descriptive on what it really is.

Aralmo | mailto:aralmoAT NOSPAMgmail dot com | aralmoAT NOSPAMgmail dot com

07/18/2008 12:31 PM

data makes more sense than state (what you pass to that method is not always a state or related to that)

BUT

I have absolutely no problem with state as long as I know what it does [which I do, thanks to msdn :) ]

Waheed | mailto:waheedahmedbAT NOSPAMgmail dot com | waheedahmedbAT NOSPAMgmail dot com

07/23/2008 1:28 AM

Making a fuzz about the names of variables is right up my alley. :)

My vote is for state, but in a perfect world everyone would move to C# and we could loose the 'null' at the end to get:

request.BeginGetResponse(result => { ProcessResponse(request.EndGetResponse(result)); });


Now lets assume we have another option of making clear what the variable is for... eehmm...
//TODO: Say something wiseguyish about documentation..

Ralph | mailto:ralphAT NOSPAMaffy dot nl | ralphAT NOSPAMaffy dot nl

07/24/2008 12:38 PM

We've used the term "Cargo" for that kind of thing. "I'm just carrying this for someone else, I don't know/care what it is. I'll let them assume any legal responsibilities for what it is and how its used".

Starsky

08/03/2008 4:57 AM

I agree; "state" is the best name. Shame it wasn't used throughout the framework. It matches the IAsyncResult.AsyncState property name just fine. Prefixing with "async" does nothing for readability or understandability.

More like: if only changing the name of IAsyncResult weren't a breaking change, maybe more people would do async programming!

Pete

11/19/2008 2:11 AM

I always use async calls for I/O (especially sockets) and I tend to have a context object which gets passed through that parameter. It's not always a state so I would vote against anything that says "state" personally. I vote for context as a name because it's a context within which the async calls are operating.

I also like Starsky's "cargo" though - it describes what it is very well.

Alan | http://www.benchmarx.com | alan dot kellyAT NOSPAMbenchmarx dot com

Add New

Name

Email

Homepage

Security Word

Type in the security Word

Content (HTML not allowed)