Design guidelines for C++

I'm here at PDC, and it hass been great to meet so many C++
developers. Of course, the best part of this week is that Visual C++ has finally
announced the new language design for C++. As I mentioned last time, I will
spend a while covering rationale and design behind this language design. Before
going through the design process and some of the history in the language, I'll
cover highlights of what we learned from managed extensions.

  1. Keeping compatibility with existing C++ was really
    great. This is what we have colloquially called "It Just Works" or IJW.
    Giving C++ developers seamless interop between unmanaged and managed code
    was the killer feature. We needed to preserve this advantage and look at
    making it even better.
  2. People hate underscore-underscore keywords. Even
    though this was done to work well with the C++ Standard (and developers
    understood that), no one really liked it. Going forward we needed to look at
    different ways to have first-class keywords but maintain compatibility with
    existing C++ code.
  3. Overloading the meaning of the same syntax makes the
    language hard to use. Nowhere is this more obvious than with pointers. An
    asterisk in the managed extensions syntax meant one of several things: (1) a
    native pointer in which memory did not move, (2) an interior pointer in
    which memory could move and it often pointed inside an object, or (3) a
    whole object pointer in which memory could move. Looking at single line of
    code and determining which kind of pointer was in use was sometimes
    impossible. We learned that different concepts need to be expressed with
    different syntax.

I could go on forever on lessons learned. A frequent
message that we heard was developers like C++ and wanted to use it, but managed
extensions were just too hard to use. More concerning is that some of the design
decisions in managed extensions actually prevented us from innovating in the
language. For example, the usage of pointers made it impossible to make use of
operator overloading CLR types, as user defined operators do not apply to
pointers. Based on significant feedback, we decided to redesign the CLR features
in C++.

Several things have greatly benefited the new language
design. First, we actively sought feedback from C++ community leaders. Compiler
vendors, library developers, and others were involved very early on. They were
given the opportunity to provide feedback, and we listened and acted. Second, we
started by setting goals for the language design. As more people were involved,
it was easier to get randomized with different approaches to solving problems.
By having a list of goals available, we were able to measure each of these
solutions.

Many people from Microsoft were involved in creating a
solid language design. From the compiler side, Mark Hall and Jonathan Caves have
brought significant experience in writing the Visual C++ compiler and doing much
of the work that made the Managed Extensions language possible. Jeff Peil
brought a wealth of knowledge about the C++ standard, the internal working of
the CLR, and a keen understanding of how C++ is used in production. Chris Lucas
led the language design team for a while to set the goals and direction for the
language design. Herb Sutter facilitated the community involvement and
standardization process, and recently started leading the design team to guide
it through some difficult decisions. Anson Tsao and Martyn Lovell have been
involved from the libraries aspect – both building libraries with the new
language and ensuring common C++ practices were enabled by the language design.
Finally, I have been involved working on the language semantics, implementation
schedule, and language specification document. Of course there a dozens more
people who are implementing this language and actively involved in the design.
As I cover more specific areas, I will mention who was involved.

Knowing that, Chris Lucas is the one to thank for setting
the language design team in the right direction. Extending a language is much
more difficult than creating a new language from scratch. He started by reading
Bjarne Stroustrup's book, "The Design and Evolution of C++." Many of the design
goals of C++ still resonated today, and they were adapted to the goals we
finalized upon. Here is a summary of those goals:

General Rule

  • Using CLR features is an option, not a requirement for
    C++ development.

Design Rules

  • Solve problems developers have today.
  • The CLR features are a first class part of the
    language, we need to make the experience seamless.
  • Enable good designs to be written. Even though C++ has
    significant flexibility, we need to enable good developers to write robust,
    correct, and maintainable code.
  • C++ is, and should always be, a multi-paradigm
    language. We need to support existing paradigms (object oriented,
    procedural, and generic) in everything we do. We should also make sure new
    features are orthogonal so that the combination of features yields an even
    more powerful language.
  • Consider the interaction with other .NET languages.
    These aren't always just paradigm issues. We need to make sure that
    frameworks programming is easy with C++.
  • We should have aspirations for standardization and
    growth in the CLR support, but prioritize making C++ useful and productive
    today.

Technical Rules

  • Care needs to be taken to preserve C++ semantics versus exposing
    CLR semantics. Using both semantics at the same time is ideal.
  • Syntax should have a distinct and consistent meaning.
  • It's more important to enable C++ and CLR features, than it is to
    disable them for CLS compliance. It should be obvious when a developer is
    writing CLS compliant interfaces, and tools should assist the developer. If a
    feature could be CLS compliant, make it CLS compliant.
  • We should not avoid a feature due to verifiability, but we should
    ensure that it is possible to write productive, useful verifiable code in C++.
    It should be easy for a developer to recognize when code is verifiable or not.
    If a feature could be verifiable, make it verifiable.

Support Rules

  • Leave no room for a lower level language on the CLR
    than C++.
  • Don't sacrifice the scalability of the C++ build
    process.
  • Support the creation of CLS compliant interfaces and
    verifiable components.
  • Support assembly, module, and compiland organization
    of code.
  • The language enables the library which enables the
    application.

There is a lot behind each of these rules. I'll spare
everyone from an in depth discussion of each one (someday it will probably end
up in a book). In the end, we had a very simple mantra that the language design
team lived by: Bring C++ to .NET. Bring .NET to C++. In that short phrase
lies a lot of power. C++ has so much to offer, as does .NET. It was our goal to
bring the best of both worlds together. In many ways, we believe we've succeeded
at tackling this challenge. As we continue to gain experience and feedback, we
are confident that C++ will continue to provide the power and flexibility that
make C++ developers the best in the world.

Next time, I'll share some
of the things I've heard at PDC as well as provide some background on the type
of developer the Visual C++ group is building a product for.