1/ @werat asked about whether the debugger was using the C# compiler or language service in VS 2002. It was not. The debugger has a component called an ‘expression evaluator’ that is provided per language and is responsible for parsing and evaluating expressions when stopped at a
2/ breakpoint. For example, if you type into the immediate window, hover over a variable, type into the watch window, etc. the expression evaluator is involved. The debugger and the language service are actually deeply integrated in a number of scenarios in VS, which may
3/ initially seem surprising. I may talk about more of these scenarios in the future, but to give a flavor, when you set a breakpoint at design time the language service is involved, when you are using Edit and Continue the LS is involved, the range of what is being evaluated
4/ when you get a debugger data tip, completion lists when typing in the data windows or immediate window, etc. Prior to VS 2002, there were distinct debug environments tailored to each target customer (VB/VBA, C++, VJ, VBScript, TSQL, FoxPro, Fortran, etc.). The goals of the
5/ VS 2002 debugger included unifying the debugger backend components and providing a single UI stack that would enable new scenarios (for example, a callstack across languages). Expression evaluators are the architecture that separate the language specific pieces from the
6/ agnostic parts. However, as the C# team was comparatively small, in VS 2002, the debugger team implemented the expression evaluator for C#. The debugger team decided to implement a single expression evaluator that would cover ‘managed C++’ and C#, which made sense originally
7/ likely as it wasn’t clear how different C# would be. Unfortunately, the ownership and implementation choice led to a fair bit of pain because the language would change so rapidly it was really unreasonable to expect the debugger team could keep track.
8/ Regardless, the EE for C# was implemented in mcee_cs.dll, and provided fairly basic evaluation. The joke on the team was that the EE had only a single error message which was ‘managed EE does not understand expression’s syntax.’
9/ TBH, it wasn’t far from the truth and unfortunately, it made the debugger significantly less powerful than it could have been as hover, evaluation in data windows, the immediate window, etc. were all impacted. The debugger also had this irritating property of evaluating
10/ expressions multiple times when refreshing UI, so if your evaluation happened to cause side-effects, your debugging state became untenable. That’s probably a separate thread though, so let’s just say, that we knew this was a problem but didn’t have time to address it for VS
11/ 2002. We started working on a new EE that was based on the *compiler* code base quickly thereafter, though it didn’t ship until VS 2005. We chose the compiler codebase versus the language service codebase, as we wanted it to be as faithful to the language as possible.
12/ We didn’t really have the architecture to treat the compiler as a service as that point in time, so the way this was done was by introducing a series of #ifdefs within the compiler codebase that implemented EE specific functionality.
13/ This did complicate the codebase, but enabled code-sharing. We produced a new csee.dll that was essentially the compiler with a different #define enabled on build. I am proud of the customer experience we achieved in VS 2005 with this change as it drastically improved the
14/ debugger experience both in terms of visualization and dynamic inspection. I’ll dig into this later, but just as an example, here is what the VS 2002/2003 view of DateTime looked like in the debugger versus what it looked like in VS 2005.
• • •
Missing some Tweet in this thread? You can try to
force a refresh
1/ In early 2004 we were heads down executing on Edit and Continue across a large contingent of teams. There had been several iterations of scoping, redesigns, and customer feedback.
2/ We had a weekly meeting every Thursday morning when representatives from each of the teams would get together and review progress. It was fairly heavy weight, but there were so many teams involved that it was necessary to have a regular sync.
3/ Regardless, E&C was coalescing, but teams were stretched thin working diligently to enable scenarios, improve performance, fix bugs, etc. It had been a month or so since we decided to add support for C# to the matrix as well, so folks were a bit stressed.
1/ Edit and continue was a beloved feature of VB6 and was a priority for making migration onto .NET easy for RAD developers. EnC is magical when it works correctly. For web developers that are used to hot reloading, it enables that type of rapid development, but maintains state.
2/ Unfortunately, it is an extremely difficult feature to implement in a JIT'ed world as we discovered that with .NET 1.0. We actually had a version of EnC in the early releases of VS 2002.
3/ I'm fairly sure it persisted all the way up to Beta 1, though the history of when we removed it is a little hazy. The initial implementation wasn't coalescing. There were a huge number of bugs, it performed poorly, and it often corrupted the debuggee.
1/ I haven't mentioned much about C# integration into Visual Studio yet, but at the same time we were working on creating a new language, a new runtime, and a new framework we also decided to take disparate shells (MSDEV, devenv, VB6) and combine them. This was… a lot.
2/ As you might expect, taking on so much at the same time meant a very long development cycle. For those folks using VS6 it was a long wait for VS7 (‘98 to ’02). Regardless, we wanted to continue to provide a compelling LOB (line of business) client app framework while also
3/ enabling web apps (via ASP.NET, web forms/services, etc.). The client app framework manifested as Windows Forms and was the next iteration of a RAD app creation environment. The Windows Forms designer is extremely rich and intended to make developing UI-rich
1/ An interesting bit of history for .NET and C# is that there used to be a public System.Variant type. It was actually a keyword in C# for a while, alongside of object. If you’re unfamiliar with variants, they are a tagged union type.
2/ This means that they can represent many different data types and contain a ‘tag’ (a small enumeration) that defines the type of data they hold. This evolved because COM uses variants heavily, as did VB6 (and many other languages).
3/ In the original iterations of VB.NET, Variant was used for any untyped declaration (e.g. Dim a, b). Variants and System.Object are similar in some ways, and as you might guess, this led to problems.
1/ The C# development team, for V1, consisted of 5 individual engineers, a lead, and a couple of PMs. 4 of the engineers worked on implementing the compiler, and the last engineer worked on the Visual Studio integration (e.g., IntelliSense).
2/ The C# compiler was written entirely in C++ as was much of Visual Studio at the time. Everyone on the team wanted to implement the compiler in C#, but as I mentioned previously, expediency was key and when we started, we needed to bootstrap. That was done in C++, so it stuck.
3/ The compiler was largely implemented as a batch compiler. We had a no-release heap, which was extremely efficient for straight-through compilation and totally useless for interactive scenarios. Therefore, the compiler and what we call the language service were implemented
1/ It's probably not the first thing you think of, but when we started .NET (COM+) in the late 90s, C# didn't exist yet. We were working on it at the same time as the CLR and the framework. So, you might wonder, what language was being used to generate IL and write the BCL?
2/ The answer is a language that we called SMC that Peter Kukol wrote the compiler for. Peter is a flat out amazing engineer and wrote the core parts of the compiler in just a few days. This unblocked the framework team, allowed vetting the runtime and interpreter, etc.
3/ SMC was a trimmed down C++ variant and the compiler was written in itself (i.e. SMC). It didn't support things like destructors, multiple inheritance, virtual base classes, etc. But, overall it enabled progress that would have otherwise been stalled.