Or… more cancelled projects I worked on in the early 90s…
I wrote a bit about C#88 last week and I teased that this project, and more importantly its members, went on to do some pretty cool things. I want to write today a bit about “Sequoia” an IDE that never shipped, based on some of the notions that came out the C# project, or, more importantly, its death.
When C# was cancelled, some of its members (like myself) were redistributed to other teams (I went on to work on PWB for a time). Other members had a short period to do some research on what they thought a good development environment might be like. There were many discussions but the outcome was a series of memos that described “ADE” the Advanced Development Environment. A thing which I’m sure you never heard of because it never shipped… The ADE memos provided the base architecture of the Sequoia project which was kicked off shortly after C6 shipped. I was one of the founding developers having remained familiar with the work on ADE which was largely done by close friends.
As I write what follows I’m sure some of it will ring familiar because it had broad influence, but I can assure you all of the code ultimately died. I apologize for the rambling nature of this story… mostly I just wanted to get this written down somewhere before it was all lost.
ADE and Sequoia embraced C++ templates and multiple inheritance. I’m not sure if I would go down that road again. Being as we were still using a CFront style C++ pre-processor it meant that templates had to be done via a preprocessing tool. So Foo<int> turned into Foo_int after the expansion phase. This was a lot more limited than what you can do with templates today but it did give us type-safe parameterized collections for instance.
Most reference types inherited from “DYN” which provided two features: reference counting and DynCast, which could cast a pointer of one type into a pointer of another type if the object supported that type. If this sounds familiar it should. The value type REF<T> provided automatic reference counted pointers and was widely used.
Central to the idea of ADE was “selection based tool integration” meaning that assorted objects in the IDE might inspect the selection, see if it was for example “a thing you can put a breakpoint on” and if so, ask it to set the breakpoint. But I’m getting ahead of myself.
Also omnipresent were Events, so a number of objects produced and consumed events. This was modeled as a base type T for the event methods and then two subtypes EVTG<T> and EVTR<T> for the event generator and receiver respectively. Note that both have the T type signature so the method names are guaranteed to match. Wow high tech type checking or what huh? Pretty amazing when you were used to switch statements and decoding wParam and lParam…
Documents and Document Components
Avoiding display for a moment, lets start with the “model” part of the picture, a document “DOC” consumed some kind of document position “DP” currency, usually a value type and gave you a durable document component “DC”. There was no base type for DP because we found that they tended to have nothing to do with each other, but the notion of DP was still a useful one. The DC was durable in the sense that even after modifications, every attempt was made to have the DC refer to the same piece of the document. As a result virtually every DOC had to track its outstanding DCs. Note: A DP could be, and often was, a range.
An example might be helpful. We had a Grid document. The DPs were a pair (row, col) and the DC was a particular cell. If you got a DC for position 5,2 then it would refer to the same cell contents even if a row was inserted. A DC could give you back its current DP.
Documents always provided a generic “something has changed” notification event, and generally subscribers would use DYN to get a better interface to get more details about the particular change.
Give all the above it’s pretty easy to do a general purpose selection object SEL, which basically holds an array of DCs and provides change notification when it changes. So there was a selection changed event.
So at this point you could imagine writing a tool that listens to the selection, looks to see if the selection is of a suitable type, and then lights up something accordingly. More on that later.
Views (VIEW) generally consume some kind of DOC and generally subscribe to the DOC change event. But all they really are required to do is Paint a provided rectangle, and hit test (given a point, return a DC). Many views did more than this but the basic contract was very simple. A popular subtype provided for scrolling (which only required the view to remember its new origin).
View Controller, especially Host View Controller
These corresponded to the underlying windows of the OS. Originally Sequoia ran on OS/2 but ultimately it would also have to run on Windows. Most of the code didn’t know about this kind of stuff. The HostVC created a “window thing” and got the underlying messages and turned them into the standard UI events. Any number of objects could subscribe to some or all of the events and the subscription tended to be pretty fine-grained. I never really liked the name of this class…
Most actual UI responsiveness was handled by the class TOOL. Typically the TOOL finds the relevant VC, subscribes to some events, and then manipulates the DOC or the VIEW appropriately in response to the gesture. So TOOL is a lot like the usual “controller” in MVC. But there’s more details there as well.
Tools do not actually manipulate the DOC or the VIEW directly. The IDE needed to be scriptable and in particular it needed to support “record mode” so that meant everything that ever happened had to go through some kind of common pipeline. Commands were for this. In addition to the usual DYN stuff COMMAND provided “Do” and “CanDo” so you could ask a command if it could do its thing on its current target (typically the selection, but some commands did other things, like scrolling).
Since every verb in the IDE was scriptable there would be 1000s of commands and classes were not cheap so we made “cheap command” which basically was a single class where you could plug in two pointers to functions for Do and CanDo. Virtually everything was a cheap command.
For scripting we used “Embedded Basic” which was the very same basic that powered Visual Basic. If record mode was on then “the script you could have run to do what you just did” was logged.
To make all this sane we needed a container, so when you put a VC, some TOOLS, a SEL, a DOC, and some VIEWs together you get a TOOLGROUP. Lots of TOOLS could add themselves to a group just by asking for the SEL or DOC etc. But many tool groups had specific wiring that was needed to get everything to work. The TOOLGROUP knew how things hung together so that other things didn’t have to.
All key processing was done view a central KEYMAP. Any given VC had a current keymap id. This id was used along with keypress events to convert the keypresses into commands. Each keymap id had a parent id so it was pretty easy to have global keys and override them. Things like editing modes could be easily accomplished simply by changing current the keymap id for a given VC. With this kind of flexible key mapping support (nearly instantly change to a different mapping) and decent editing primitives an intern was able to write code in Basic to emulate VI.
These could be done generically, you bind a command to the toolbar slot along with an icon. The icon is automatically grayed depending on how the command responds to CanDo and clicking does the Do. Toolbars tended to refresh on selection change and were associated with a particular toolgroup.
What We Build With This
Well, I could go on for a very long time talking about specific features but it’s worth going over the main inventory of stuff:
- a graph visualizer used for making things like class diagrams, it could consume a variety of graph sources
- the same visualizer was used for the build system, which let you define build rules in a graph and script them in basic (there were defaults for all the usual stuff like “compile these C files”
- a grid doc and view for a variety of displays, lots of things could be gridified
- a text document and view that used “piece tables” for quick editing and DC tracking, it provided variable size fonts and colors and did full syntax coloring among other things
- a set of debugger features including breakpoints and what not, keeping in mind this all had to run on Windows 3.1 so threading wasn’t there — that left you with the usual debugging pain-in-the-behind that is “soft mode” (I’ve written about this elsewhere)
- Various VCs for thin windows, floating windows, docked windows, etc.
All in all it was pretty amazing. The original Sequoia was specced out in several hundred pages and would have taken far to long to build so it was downsized to “Bonsai” which was still too big, so that was downsized to “Bonfire” which was ultimately cancelled…
And if any of this sounds like it influenced OLE, and Visual Studio, that’s because it did. Not the code, but the people.