Most of what a compiler designer comes up with is static. For example, in C#, you define a class by placing the keyword class
before the class name. You then signify derivation by inserting a colon after the class name followed by the name of the base class. This is an example of a decision that, once made by the language designer, can't be changed.
Now, the people who write compilers are darn good at what they do. However, even they can't anticipate all the future developments in our industry and how those developments will alter how programmers want to express their types in a given language. For example, how do you create the relationship between a class in C++ and a documentation URL for that class? Or how do you associate the specific members of a C++ class with the XML fields for your company's new business-to-business solution? Because C++ was designed many years before the advent of the Internet and protocols such as XML, it's not easy to perform either of these tasks.
Until now, the solutions to problems like these involved storing extra information in a separate file (DEF, IDL, and so on) that was then loosely associated with the type or member in question. Because the compiler has no knowledge of the separate file or the code-generated relationship between your class and the file, this approach is usually called a "disconnected solution." The main problem is that the class is no longer "self-describing"—that is, a user can no longer look at the class definition by itself and know everything about that class. One advantage of a self-describing component is that the compiler and run time can ensure that the rules associated with the component are adhered to. Additionally, a self-describing component is easier to maintain because the developer can see all the information related to the component in one place.
This has been the way of the world for many decades of compiler evolution. The language designers try to determine what you'll need the language to do, they design the compiler with those capabilities, and, for better or worse, those are the capabilities you have until another compiler comes along. That is, until now. C# offers a different paradigm, which stems from the introduction of a feature called attributes
.