Not all AnonymousMethods are the same

Sun, September 14, 2008, 11:12 PM under dotNET
Whilst debugging code that uses multiple anonymous methods (or lambdas) from a single method combined with multiple Threads, an interesting issue surfaces with the stack frames that Visual Studio 2008 presents.

Can you spot the problem with the following screenshot (original code from this post)? Look at the Location column of the Threads window:

Are both of those Threads with the same location string (Program.Main.AnonymousMethod) at the same place in the code editor? Look at the code editor and the answer is no. The icons with the blue and red “cloth threads” in the gutter of the editor show the two locations: one is at t2.Wait and the other at the Console.WriteLine (you can verify this by hovering over the icons to see the tooltip with Thread info).

Bottom line: The Location column (and Stack Tip) of the Threads window (and the Call Stack window in fact) are not telling you the full truth. They are indicating that thread execution is in some anonymous method, but they are not distinguishing between different anonymous methods. It would be nice if they at least appended a number to the string: AnonymousMethod1 AnonymousMethod2, etc.

Aside: The real method name of the anonymous method in IL code starts with a chevron and is generally funky and it wouldn't add value to be displayed here. All we need is the ability to distinguish between different anonymous methods in the debugger tool windows, hence my suggestion above about suffixing them with a number. Do you have a better suggestion?
Monday, 15 September 2008 01:50:00 (Pacific Daylight Time, UTC-07:00)
I can see what you're saying here, however:

If we factored out the anonymous method into two 'normal' methods then the debugger would still behave in exactly the same way - it would be able to tell us that there are two threads located in the body, but would still be unable to distinguish between the two.

To isolate one thread, we can always freeze all but one of the threads and then continue execution using F11 (step) - after that it'll become apparent which one was where.

Also, a best practise is to give our threads a Name following a similar notation to that which you are describing. Once a thread has a name, you can then hover over the thread icon in the gutter, and a helpful tooltip appears showing not only the ID of the thread, but it's name as well.

One suggestion that further enhances the debugger experience, however, would be to be able to assign custom colours to worker threads in the 'Category' column and then to colour the execution pointer arrow accordingly. It seems that only two colours are used - green for the main thread, and yellow for all the others - ergo there's a lot of other hues available to us! If we could assign colours to threads, and then see colour indicators in the source along with the thread symbols - then we wouldn't need the tooltip.
Monday, 15 September 2008 04:58:00 (Pacific Daylight Time, UTC-07:00)
Line-number, perhaps? I don't think a running number adds too much information, as it's difficult to see the inner anonymous ones, or to know how the ide counts them.

I think line-numbers cause less mental conversions as well, as we don't have to interpret the real meaning.
Monday, 15 September 2008 10:21:00 (Pacific Daylight Time, UTC-07:00)
Could these anonymous method names show up outside the debugger somehow? Perhaps in a crash report or a log file of some sort.

In this case I think being able to distinguish anonymous methods is important but not enough. You also need to be able to take a given name and locate the corresponding code outside the debugger.

Suffixing them with a number would be good but its kind of arbitrary and it might be difficult to trace back to a specific version of the originating code file. It would be less arbitrary to suffix each with the line number it was declared on. If there is more than one on a given line then also append some separator character and the column number.
Monday, 15 September 2008 18:58:02 (Pacific Daylight Time, UTC-07:00)
andras: Thanks for bringing up 4 separate issues.

RE: factoring out
If we factored out the anonymous methods into two normal methods on the same type, we would have to choose different names for the 2 methods, so the debugger views would allow you to distinguish between the 2.

RE: Freezing
I am guessing that your comment about freezing is aimed at the scenario of having 2 threads in the *same* method: you don’t need to go to freezing extents; just hover over the cloth threads icon and you can see the Thread Ids (as I hinted at in my blog post above).

RE: Naming
I agree that Threads should have names (see my blog post here). Indeed, that would be a nice enhancement to the tooltip I mention above. However, note that ThreadPool threads or threads assigned to Tasks do not have names since by definition they are not dedicated to a single work item.

RE: colors
I'll pass that on ;-)

Thomas: The goal here is to quickly distinguish between more than 1 anonymousmethod defined in the same method. I agree that if we wanted to go *beyond distinguishing* to actually relating back from the call stack window then line numbers is the answer. This already exists in the Call Stack window if you turn line numbers on.

Brian: Remember that this issue only arises when you have more than one anonymousmethod in the same method. However, that is irrelevant I think, because in crash reports I would hope you have the line number, parameter types/values and those should help you figure out what went wrong. The goal of distinguishing is more about: "I just hit a breakpoint, are my threads running in the same method so I can focus debugging in that area?". Also, if you were to get the actual method as it appears in IL, there is already a number embedded in the obfuscated generated name, and one would hope that would be the same number that was appended ;-)
Comments are closed.