Sorry about the lack of updates. I haven’t been able to work on the Managed Language Service like I wanted to. Instead I went on a great vacation and then have been spending most of my time doing a lot of in depth security work on the C# language service. I’m not sure if I can talk about what we’ve done, but I’ll try to find out so I can write a post (or few) on that later.
So we’ve run into an interesting situation and we’re trying to figure out the best plan of attack for Beta2 (and for VS2005 in general). Best to dive right into specifics. In VS2003 we had a feature called “auto-complete on override” (AoO). The way it worked was that if you typed:
then we’d pop up a list of all methods, properties and indexers that were available to be overridden. After choosing the item you wanted we’d then spit out code like:
public override int GetHashCode()
Now, we received a lot of requests from customers who used features like this and “implement interface” and “+= on events” that they wanted more control over the code that was injected into the source. In order accommodate that, and also to enable some new features we wanted to provide, we developed the “expansions” feature that you can see in VS2005. These “expansions” use special user-editable .snippet files that can contain pretty much anything. They’ve got an XML schema that defines them and they feature specialized capabilities like the ability have programmatically replaceable fields.
So now we started using these “snippets” extensively and replaced all the places where we spit out a method to now use the snippet instead. To give you an idea of what that looks like, here’s the content of the MethodStub.snippet file:
<?xml version="1.0" encoding="utf-8"?>
<Title>Method Stub - Body</Title>
<Description>Snippet for generating method stub with a body</Description>
$end$throw new $Exception$("The method or operation is not implemented.");
There’s a lot to digest, but really the most important components are the “literals” and the section inside the “code” tags. Inside that you’ll see the $signature$” field. This field will get replaced by the language service with the signature of the method being overridden. Next is the $end$ field. This designates where the cursor will be placed after the expansion is inserted. Finally there’s the $Exception$” field. This one is a little different. If you look at:
you’ll see that the $Exception$ field witll get expanded out into a function call to SimpleTypeName(global::System.Exception). The way that SimpleTypeName works is that it will use the “usings” in scope to pick the best possible name for the typename specified as its argument. That way if you have a “using System;” then we’ll inject “throw new Exception(…)” whereas if you don’t have that “using” then we’ll inject “throw new System.Exception(…)”.
Remember, this file is user editable. So by having this expansion, the user now has the ability to configure much of the code that is spit out. They can now add comments. Throw their own exceptions. Have a default doc-comment included by default. Etc.
So what does this mean? Well, between VS2003 and VS2005 we’ve changed the behavior of the AoO so that instead of getting:
throw new Exception(…);
What’s worse is that there is no way to get back to the original behavior. i.e. you could change the snippet file to not throw the exception, but there’s no way to configure it to call the base method correctly (as that would require know far more information than is exposed to the snippet engine).
We received quite a few complaints about this internally and from ProductFeedback: http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=f0799869-79f0-4aa8-91d9-b2250dbc6a91
At first we figured that we would postpone adding this functionality back in a later release. We felt that while it was unfortunate that we were breaking old behavior it just wasn’t that big a deal. After all, a user could just manually make the call to “base” themselves. However, just recently we realized that our change was actually fairly detrimental to the user. Why? Well, for the correct functioning of overridable methods it’s often the case that the code must call the base method. Forgetting to do this can lead to subtle bugs where the consistency of the base object is not longer valid. By always injecting the base call we were putting that fact right in the face of the programmer and allowing them to remove it if they knew it was the right thing to do.
So we have a dilemma (albeit a minor one) right now. We can continue to ship the way the product works today. Do nothing and tell users “sorry, you can’t get the old behavior and you’ll have to manually fix up overrides.” Or suck it up and add back this functionality in a way that works with the current snippet architecture. i.e. we would most likely introduce a snippet that would have contents like this:
throw new $Exception$("The method or operation is not implemented.");
(note the addition of $CallBase$). This field would then expand to the relevant call to the base method, property or indexer.
Why wouldn’t we do the latter? Well, we’re focusing on security right now and absolutely getting VS2005 up to extremely high quality for the beta2 release. This is the VS released under the “go live” license, meaning you can develop web sites and software that you are allowed to release/sell/whatever. So it’s paramount that these tools be working very well. Toward that end we are fixing the bugs we consider important and, in general, postponing anything else unless we feel that there is enough user need to warrant their inclusion.
So what we’re trying to find out is how important this feature is to you. To you feel that it’s important enough to be re-added very late in the cycle (with the possibility of delaying beta2!), or should it be left out?
Let us know! Tell us here (or on ProductFeedback) so that we’ll know what the right thing to do is!