The Future of Language: Symmetry or Broken Symmetry?James O. Coplien Bell Laboratories, ILIE00 2Z307, 263 Shuman Blvd, Naperville, IL 60566 USA, +16307135384, cope@research.belllabs.com AbstractThe human mind works hard at being efficient. By representing information in terms of symmetries, it can reduce the amount of data necessary to represent a given piece of information. This efficiency manifests itself in the design of programming languages, artificially created languages designed to serve the intellectual endeavor of programming. Nature has elements of symmetry, too, and our mind's efficiency is perhaps nature's legacy. But nature rarely exhibits perfect symmetry. Rather, the structure of nature is dominated by fractalized structures that are the result of a process called symmetrybreaking . The stated goal of object orientation—and in fact of all software design—is to capture the structure of the domain in the code, and intentionality is of growing import in language design. The lack of parallelism in symmetry between nature and programming languages is one reason programming is hard. In addition to the usual features that support symmetry, C++ in particular has strange features that express symmetrybreaking. Which should dominate a language: concern for nature, or the mind? Is there a minimal set of symmetrybreaking features for a language? How should C++ evolve to bridge the design gap—or should it stay just as it is? I'm in a Research department at Bell Laboratories. I've been invited here to talk about the future of programming language and, indeed, that's where this will eventually head. But one of the casualties of inviting researchers is that they'll want to find a way to talk about their current work, and I've given in to that temptation to get us started. Trust me, well come around to talking about C++ and its strengths and its problems. But we'll do so in a much broader context, a context necessary to such a serious question as the future of a programming language. C++ has evolved largely out of pragmatic considerations; Stroustrup can go on for a half hour talking about any language feature you choose, describing the tradeoffs that were brought to the table and how the tradeoffs were addressed, and why they were addressed the way they were. It's important to sit back once in a while to reflect, integrate, and to more broadly tie things together.
PatternsI'd like to start with a little tutorial about patterns, because it can help provide a strong design foundation for language. Most of us believe patterns are just captured wisdom, but the semantics are much richer and relevant to programming structure than that. A pattern is not only a process and a thing, but its a spatial configuration involving that thing. And that thing lives in the larger (spatial) context of other patterns. Together, the patterns form a language. By "language" we mean that there are rules for assembling the patterns: a grammar, if you will. The grammar itself is almost as much a part of the pattern language as are the individual patterns. I can restate this by saying that a pattern is a transformation that preserves the overall structure of a system, adding structure through a process of piecemeal growth. It is a function that maps one version of system structure onto a refined structure. During this mapping, structure is preserved, and the basic symmetries are preserved—however, the symmetries may be redistributed. As an example, consider the pattern ENTRANCE TRANSITION [2]. It represents a symmetry between an "outside" and an "inside." If you add an entryway, or a wooded path, or a nice walkway between the "outside" and "inside", it adds local symmetries. Look at the above starfish. Now close your eyes. O.K., now open then again. While they were closed, I rotated this starfish. Did you notice? It looks the same as it did before you closed your eyes, and the reason it looks the same is because of symmetry. We can mathematically formalize the notion of symmetry. If a system has symmetry, it means that something stays the same under a welldefined set of changes. We can collect those changes together into a set called a symmetry group. That set, together with a formal definition of what it means to "be the same", define the symmetry of the starfish. What it means to "be the same" is that it looks the same. We can judge two starfish as being the same, or equal, if they look the same. This is the definition of equality or "sameness" that is the foundation of symmetry. We can formalize that equality according to isometries in a planar geometry: the starfish doesn't stretch or warp, for example. So there are ten transformations we can apply to a starfish that keep it looking the same: five rotations, each a multiple of 72º, and five "flips" about the axis of the starfish arms. Actually, there are an infinitely greater number of such functions if we keep rotating the starfish beyond 360º, but we cant distinguish them from the more primitive rotations. We make a set of these ten functions, or transformations, and call it the symmetry group of the starfish. A group is just a special kind of set that has an identity, an inverse, closure, and associativity. Let X = L (line), P (plane), or S (3D space), and let AX. A symmetry of A is an isometry T:XX which leaves A invariant. The set For those of you are formal mathematicians, we can formalize what it means to be a group. Note the definition contains the following properties:
Elegantly Symmetric SoftwareSo now let's talk about software. What does symmetry mean? We find one simple and obvious symmetry in the structure of the source code. Dont laugh—symmetry in the source code matters. There is anecdotal evidence that indentation style and fault density correlate. But we can go deeper. Consider the foundations of objectoriented programming as formalized in the Liskov Substitution Principle: If for each object o_{1} of type S there is an object o_{2} of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o_{1} is substituted for o_{2}, them S is a subtype of T. [4] It's a symmetry! Look at the words in the above definition: there is a definition of something that is "unchanged" or equal—namely, the behavior of the program—while something changes—namely, substituting a derived class in a base class context. This is the polymorphism that is at the foundation of the software organization supported by objectoriented programming. We can formalize this symmetry as a symmetry group. Each derivation is an element of the group Symm(B). The group B comprises all inheritance transformations D on the program P, that the programs behavior B is invariant with respect to D. But the LSP isn't the only symmetry in software. There is more to programming than object orientation; C++ is a multiparadigm language that supports many different kinds of software structure. But that's another talk. Here, we can look at inheritance as a symmetry apart from the Liskov Substituion Principle. In the above definition of symmetry groups, think of:
And, in fact, you can take just about any feature of C++ and characterize it as a symmetry. Weve already looked at inheritance and subtyping. A function call can have preconditions and postconditions as invariants (definitions of equality) and be called from different, varying contexts; there is symmetry between the function calls themselves. Declaration and instantiation are symmetries as well; all instances are similar, but different. Loops are spiral symmetries in time—a bit strange, perhaps, but time also has structure. And its not only C++ where we find symmetry holding sway; these are the fundamental building blocks of all programming languages. For these constructs to be so ubiquitous and common, there must be something deep going on. If you talk to biologists (and I have talked to them but certainly am not one), theyll tell you that the human mind tends to encode things in terms of symmetries as an efficiency measure. So most programming languages are optimized for their interface to the human mind. That's important. Symmetry is the foundation of elegance. Elegance appeals to our need for order and some feeling of control and regularity in the world. We want things to fall into place, to happen as we expect them. We like global balance and order. Unfortunately, any hope of global regularity that we can control is misplaced, and if we look for order in symmetry alone, were looking in the wrong place. SymmetryBreaking: Roots of BeautyO.K., back to physics again, to look at symmetry in the real world. Consider a falling drop of milk that is headed for a pool of milk. It's quite symmetric: looking at the drop of milk and the pool of milk from above, we can rotate them an arbitrary amount and they still look the same. Remember the starfish that we could rotate 5 different ways and flip 5 other ways? Well, here we can rotate the system an infinity of ways. But it's a limited infinity, about as big as the set of real numbers is. If a system is rotationally symmetric in one axis, we call its symmetry group O(2). So this system is all set up, and now well let it go—we let the drop fall into the pool. Something will happen: probably a splash. The initial configuration is the cause of the splash, and the splash is the result. The cause is symmetric; in particular, it has O(2) symmetry. In physics there is something called Curie's law that says that symmetry in the cause is preserved in the effect, and that asymmetry in the cause is preserved in the effect. So symmetry should be preserved. What happens when the drop falls? Well, there is some kind of symmetry in the result, but the result clearly doesn't preserve the symmetry of the cause. We can designate symmetry group of this droplet as D_{24.} This violates Curie's law. Why? It turns out that nature is never purely symmetric; it just looks that way. There are thermal excitations going on in the milk drop and in the pool of milk; there is real finelevel granularity at the molecular level that means the droplets aren't perfectly smooth. There are other forces like surface tension that get in the way of the simple rotational symmetry model. So Curies Law actually does preserve symmetry; its just that there isn't as much symmetry to preserve as the naïve model would have us believe. The lesson here is that nature isn't purely symmetric. In fact, it hardly ever is. Most constructs in nature are the result of a process called symmetrybreaking. Symmetry doesn't really break under symmetrybreaking; the variations just cause it to be redistributed. Stewart and Golubitsky note that symmetrybreaking is a foundation for configurations that physicists call patterns: This paradox, that symmetry can get lost between cause and effect, is called symmetrybreaking . In recent years scientists and mathematicians have begun to realise that it plays a major role in the formation of patterns. . From the smallest scales to the largest, many of natures patterns are a result of broken symmetry; and our aim is to open your eyes to their mathematical unity. [5] Remember that software gets its notion of patterns from an architect named Christopher Alexander. What's interesting is that Alexander was a physicist and mathematician before he was an architect, and that we can trace these ideas back through to physical foundations. Nature is rife with symmetrybreaking. So are most of our business domains. Symmetry Breaking in SoftwareSo, back to software again, where well show that this last foray into physics is just as relevant to software design as was our first look at symmetry in physics. Symmetrybreaking is as important to software design as symmetry is. Consider this example: class Complex { public: Complex &operator+=(const Complex&); . . . . private: double rpart; double ipart; }; class Real: public Complex { public: . . . . private: // ??? no ipart!!! }; Remember that we said that inheritance is a symmetry? Its a symmetry if everything in the base class propagates through to the derived class. Here we have a base class, a Complex number, which contains two real numbers. The Liskov Substitutability Principle tells us that we should subtype Real from Complex; we express that in C++ using inheritance. But if we did that, class Real would have an imaginary part. Of course, we could do that and add an invariant that the imaginary part of Real should always be zero. But in a program that deals with tens of thousands of Real numbers, such efficiency can be crucial. So the language and the hardware representation of numbers provide aberrations that cause the symmetry to break. We need to break symmetry, the symmetry we hold to be true for class Complex. How do we solve it? One way to solve this problem is with a pattern: in particular, the BRIDGE pattern. We would factor out an implementation hierarchy from an interface hierarchy. In nature, broken symmetry results in a pattern such as the milk drop. In software, the result is a pattern, too. And the similarity is more than incidental. Symmetry breaking is a phenomenon that distributes global symmetries locally. These quotes from Alexander underscore how important symmetrybreaking is to the structure of the "real world." Living things, though often symmetrical, rarely have perfect symmetry. Indeed perfect symmetry is often a mark of death in things, rather than life. Furthermore, these quotes establish a link back to symmetry breaking from Alexanders work and, by inference, establish symmetrybreaking roots for the software patterns that took Alexanders work as inspiration. Alexander believes that purely symmetric designs are dysfunctional. This has many repercussions for design. Perfect reuse is perfectly symmetric, so you need parameterization and refinement instead of simple cloning. You cant articulate a design in terms of symmetries. Beauty is about symmetry breaking, not symmetry. But this leads to a fundamental problem from a programming language perspective. There is a mismatch between the highly symmetric world of our human minds and the languages they create, and the real world that is rife with symmetry breaking. Nature has very few pure symmetries. When we design, we seek language expressions that capture the structure of "nature," of our domain. Therefore, our programs necessarily have structures that are very different from those present in the structure of the systems that they model. That means that, at best, those programs have low intentionality with respect to their domain. So programming is an attempt to capture the constructs of nature, rife with broken symmetry, in a language tuned to express symmetry. Even though most language features in most programming languages express symmetries, there are noteworthy exceptions. C++ has more than its share. What does this mean? C++, designed more from a pragmatic perspective than from the cerebral perspective of elegance, has constructs that express symmetry breaking. That means that it more directly can express realworld constructs than one can find in a pure objectoriented language. A union can express breaking the symmetry of a data structure. Argument defaulting establishes a symmetry in the value of final arguments that apply across all function calls, but a particular calling site can break the symmetry by overriding the values. Template specialization can break the symmetry of a data structure. Private inheritance breaks the kind of symmetry we find in the Liskov Substitutability Principle. If you step back and look at these features broadly, they seem to be the more controversial features of the language. It took a long time to make union initialization work. Few people know about template specialization. Private inheritance is viewed as just "strange." One thing this means is that C++ isn't pretty. Even C++ advocates recognize it. But prettiness—pure global symmetry—doesn't do the job. Something that's too symmetric, too pretty, in its design can't express important configurations that arise in nature. Looking at programming language from the perspective of symmetry and symmetry breaking provides a formal foundation for these features and their suitability to design. Programming languages exist not only as a way to implement designs, but to do so in a way that expresses the intent of the designer. This is called intentionality. Certainly part of the designer's intent is to capture the structure of the problem domain in the solution. This is the naïve expectation of object orientation. C++ goes beyond the naivté of objectorientation to incorporate multiple paradigms of expression. Each paradigm in isolation is elegant, and a good programmer can combine these paradigms in a way that leads to elegant programming. But, more than that, it has constructs that don't fit any paradigm in particular but which express some common structures of symmetry breaking: unions, template specialization, argument defaulting, and a few others. These are the things that make the language inelegant. There is little doubt about the inelegance. But they are the hallmark of languages that thrive in the hands of great programmers. Guy Steele's OOPSLA 98 keynote decried the lack of features in Java that gave expression to the kinds of local symmetries that C++ can capture. Beautiful language cannot be purely symmetric. While elegance caters to our intellectual side, communication emanates more from beauty. There are few symmetries in English or in most other natural languages. We continue to pursue elegance, yet beauty pays the bills. A Future of BeautyThe future of programming language, then, must have to do with symmetrybreaking. C and C++ are already pioneers of sorts in this area, and it will be important to continue that legacy. C++ introduced both new symmetries and new styles of symmetrybreaking to the C language. Did it go too far? Did it go far enough? MI doesn't naturally fit into models either of symmetry or symmetrybreaking, so maybe it is a candidate for retirement. Most arguments for cleaning up C++ come from a perspective of elegance and fail to recognize the value and power of broken symmetry. A language evolution path that built on symmetries alone leads to elegant languages that will always fall short of beauty. That Java begs for templates and overloading is a case in point. Smalltalk has faultered to the degree that the language syntax is overly symmetrical; it survives only at the hands of those who understand the symmetry breaking possible in the metaobject protocol of the language. Symmetry and symmetrybreaking are fundamental memes of design. They bridge the gap between what goes on in our mind and what goes on in the world around us. Languages that ignore this will fail. Any evolution of C++ that lets symmetry get the upper hand over symmetrybreaking will fail. I predict that C# as it stands will fail for exactly this reason. On the other hand, we can express complex things with the right combination of primitives. C++ has served us well. Many other programming languages, including Eiffel, C#, Java, and even C, have taken C++ as a target model for their evolution. Symmetry and symmetrybreaking provide a sound foundation for thinking about the evolution of the language. They suggest that, in fact, the language is pretty good as it is. We must avoid the temptation to give into simplistic rationales and elegance. Let beauty have its day. References
