How should a generic method be displayed?

I’ve heard several different opinions about how the debugger should display a generic method in the callstack.
Say you have a method Class<T>::Method<S>(…). Say you have 3 instances, of with (T=int, S=string), (T=int, S=object), and (T=float, S=object).  What’s more natural display?
1.)    Class<int>::Method<string>(…)

2.)    Class<int>::Method<object> (T=int, S=string, …)
        Class<int>::Method<object> (T=int, S=object, …)
        Class<float>::Method<object> (T=float, S=object, …)

3.) something else?

I think it comes down to what you’re looking for.  #1 is more natural from a high-level end-user. However, #2 is appears more natural to the low-level user. Some specific things to consider:
Generics & Code-sharing:
The CLR does code-sharing amongst generic types when applicable. ‘string’ and ‘object’ can share, but ‘int’ and ‘float’ can not.
Method<String> and Method<object> may reuse the same code. It then passes a hidden parameter so that Method<T> can evaluate typeof(T) in its body.  #2 exposes this in a natural way because it maintains the 1:1 mapping between function name and native code. This mapping can be very signficant for hard core debugging at an assembly level. Notice the shared instances have the same function name “Class<int>::Method<object>”. In contrast, #1 hides the code sharing because it provides two different function names for the same code.

Generics & the hidden parameter
#2 also exposes generic’s hidden parameter, by actually decoding it into the generic parameters and placing it in the parameter list. This can become even more signficant in optimized builds when the generic parameter has been optimized away!

Parity with language usage.
In contrast, if you want to focus on language usage and consider code-sharing and hidden parameters an implementation detail and don’t want to think about it, then #1 will be more intuitive. 

Scaling to nested generic types:
What if S=List<int>? #1 scales to this solution more easily and would become Class<int>::Method<List<int>>. It’s not clear what the correct response for style #2 even is in this case.


Comments (8)

  1. #1. No question. If you feel it’s useful enough, add an advanced option to enable #2 instead for low-level users, but don’t even think about making that the default. I had to read your text twice over to even understand why you might consider that a possibility, and I’m an advanced user compared to everyone else in my company and by extension many other debugger users.

    Please, please, don’t expose low-level implementation details like that by default.

  2. Thanks for the feedback, Stuart.

    FWIW, there is actually a school of thought strongly pushing for #2 (it has some particularly useful properties once you get to the windbg level), so your vote for #1 is important.

    I’m very interested in how others feel.

    Just to reassure everybody: end-user tools (such as VS) can consume our APIs to be able to choose either format they want. So this is mostly a question about how the tool should behave, and not how the underlying ICorDebug API should act.

  3. David Srbecky says:

    I fully agree with Stuart Ballard. I can not imagine anyone using #2 except for CLR team.

    My debugger will definatelly use #1 as a default settings.

  4. Random Reader says:

    Another vote for #1 by default. #2 requires a significant effort to understand, which is something you really don’t want of a debugging tool (until you explicitly ask for it).

  5. Soma (my boss’s boss’s boss’s boss) recently blogged about how the CLR took a major change to fix Nullable.&amp;nbsp;…

  6. Dmitriy says:

    Being a big fan of windbg. I totaly would like to see #2. Showing methods with extra parameters would very useful.

    Having said that, I can NOT imagine a common user of VS will understand that option.

    So in tools and API please make #2 available (otherwise trip to windbg will be a must), but in VS make #1 a default.

  7. RonO says:

    Agree with Stuart. #1 should be the format of the display. If it somehow becomes an option, #1 should be the default.

  8. Gustavo Guerra says:

    While I can see #2 can be usefull sometimes to get the feeling of the sharing that’s happening, #1 absolutely must be the default.