C#88: The Original C#
Every once in a while the topic of the original C# (vintage 1988) comes up. This is the project for which I was recruited to Microsoft and it was a very interesting beast, with even more interesting colleagues. I thought I would write a few notes about this system while I still remembered the basics of how it worked. Obviously a much longer article would be necessary to get everything down but you should be able to get sense of its operation from this primer. At its zenith, C#88 was able to build and run “Omega” — what you would now call Microsoft Access.
The system was designed to support incremental compilation, and that factored heavily into every design aspect. Persistent storage between compiles was provided by what we called the Global Symbol Cache (GSC). The GSC was an object oriented database that provided transactions and simple isolation. Supporting one writer and many readers, the readers all saw the database as it existed when they began their session. The writer observed its own writes as usual. Transactions and Isolation were all built using a page-mapping strategy not unlike the one used in PDB files even now… this is not a coincidence. The GSC was a cache in the sense that you could delete it and lose nothing but time.
The C# language was designed to be substantially compatible with the C programming language. As it happened the underlying compiler supported what you might call a variant of K&R C. That means function prototypes are optional, and lots of things “int” by default. The compiler produced hybrid PCode and native x86 assembly, traditional for MS applications at the time.
The compilation model was what you might get if you built something like “C.Net” today. Files could be, and were, compiled in any order, including .h files which were really not considered to be any different than .c files. The system did not do something like “scan for definitions then parse bodies” as you might expect, rather, it exploited its incremental nature to incrementally reparse out-of-order until convergence as we will see below. The team mantra was “twice incremental is still cheap.”
Source files (SRFs) were divided into source units (SRUs). A typical SRU might be a single function, or a single declaration, but they could be compound where multiple definitions were atomic (e.g int x,y;). Source units created…