06 April 2009

Mortal Kode -- Quite Simple Generics

It is very important for a tool to understand correctly what is written in the code. You just can't underestimate the importance of this ability. If the code is not correctly parsed, resolved, analyzed and understood by the tool's core, any other feature of the tool can easily fail. Nobody wants Rename refactoring to miss changes, code completion to insert unavailable symbols and code navigation to put the caret in a wrong position. Actually, the most annoying thing would be wrong code analysis, when code is incorrectly flagged with error, when in fact it compiles just fine. This all can easily happen if underlying code model is wrong.

That's why here at JetBrains, we put a lot of effort into our code model, language understanding and work hard to handle even most complex cases -- after all, they can easily be found in real applications.

Today we will look at complexity of code involving generics in C#. Consider the following example (thanks to Vladimir for this one):

  abstract class A<T>
  {
    public abstract void Foo(T x);
    public abstract class B<S> : A<B<S>>
    {
      public class C<U> : B<C<U>> 
      {
 
      }
    }
  }

I think not too many people out there can easily say what would be the correct signature for the implementation of method Foo in the nested class C<U>. As for me, I can't. Doing it manually is simply too much.

First, we try Visual Studio "override" helper and we get the following:

  public override void Foo(A<B<S>>.B<C<U>> x)
  {
    throw new NotImplementedException();
  }

Complex enough, and not quite correct:
error CS0115: 'A<T>.B<S>.C<U>.Foo(A<A<A<A<T>.B<S>>.B<A<T>.B<S>.C<U>>>.B<S>>.B<A<A<T>.B<S>>.B<A<T>.B<S>.C<U>>.C<U>>)': no suitable method found to override 
error CS0534: 'A<T>.B<S>.C<U>' does not implement inherited abstract member 'A<A<A<T>.B<S>>.B<A<T>.B<S>.C<U>>>.Foo(A<A<T>.B<S>>.B<A<T>.B<S>.C<U>>)'

Let's see what ReSharper 4.5 inserts when developer uses "Implement missing members" action from the "Generate" menu:

  public override void Foo(A<A<T>.B<S>>.B<A<T>.B<S>.C<U>> x)
  {
  }

You can see that parameter type is exactly the same as expected by compiler. Needless to say the signature is correct, and you don't have to compile it first.

Does your tool understand non-trivial code?

Next time, we'll take a look at some lambda fun.

4 comments:

Anonymous said...

OK, anyone who actually writes code like that should seriously re-think their career path.

Anonymous said...

My head just exploded

Yurik said...

Have you considered using the Mono compiler? I believe it is under MIT license, so you can easily include it into your product, and they already do all the fun stuff with code tree parsing... And it's in C#?

Plus you would be able to contribute to their project as well :)

Oren said...

Microsoft has just fixed this for the next release of VS 2010:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=463198