Over the last few years, a new programming paradigm has gained significant importance: declarative programming. It promises to make developers more productive, projects more maintainable, and in general, things much easier. Is that really true, and if so, what does it mean to conventional programming techniques such as object-oriented programming (OOP)?
What is declarative programming anyway? The easiest way to answer this question is to compare declarative programming to imperative programming. Imperative programming is what developers generally think of as “real programming.” It is done in languages like VB.NET, C#, C++, and so forth. Using imperative programming, a developer can instruct the computer to perform a specific task based on a set of instructions or commands. For instance, the following command creates a label, sets the label's caption, adds it to the collection of controls, and makes it visible (C#).
System.Windows.Forms.Label myLabel = new System.Windows.Forms.Label();
myLabel.Text = "Hello World!";
myLabel.Visible = true;
this.Controls.Add(myLabel);
The core concept of imperative programming is that the developer instructs the computer how to get a certain task done (show a label with a caption in this case). In declarative programming, on the other hand, the developer simply states what is to be achieved, and leaves it up to the system to get the job done. This is generally accomplished through some sort of meta language such as an XML markup language, or through the use of attributes. The following example shows how you could create a label declaratively.
<label Text="Hello World!" Visible="true"/>
As you can see, the declarative example is much simpler. It is easier to read, and it is also easier to create. This is no big surprise considering that you do not at all care how this would work. You simply focus on the “what.” The “how”-part is left to the system that is supposed to handle this declaration.
Now let's take this example one step further: What if you want part of the label to use a bold and/or italic font? Using declarative programming you might be able to do something like this.
<label Visible="true">He<i>ll</i>o W<b>or</b>ld!</label>
In this example, “ll” would be displayed in italics, and the letters “or” are set in bold. Things get a little more cryptic at this point, but they are still fairly simple to read and understand (as you can see by the popularity of HTML). How would you do this in imperative programming? Assuming the WinForms label control would support this sort of functionality (which it does not
), one possible way of implementing this could be like so.
System.Windows.Forms.Label myLabel = new System.Windows.Forms.Label();
myLabel.Text = "Hello World!";
myLabel.Chars[2].Font.Italic = true;
myLabel.Chars[3].Font.Italic = true;
myLabel.Chars[8].Font.Bold = true;
myLabel.Chars[9].Font.Bold = true;
myLabel.Visible = true;
this.Controls.Add(myLabel);
As you can see, this example is now getting increasingly complex. Not just that. It is also unreadable. Which letters are bold? If you said “o” and “r” you are wrong. This example actually defines “rl” as bold. Not that easy to spot, is it?
So what do you need to use declarative programming? For one, you need some sort of “system” that can execute the things you declare. A “system” that knows the “how”-part of the equation. ASP.NET is the most common declarative programming system in use today. In the future, you will be able to build Windows applications the same way using a markup language known as XAML which Microsoft Windows “Longhorn” uses to drive Avalon UI development (the next generation Windows UI technology). Third parties have even provided declarative programming support for Windows Forms. The first one to do so was a tool called XAMLON. (As you can imagine, this product has been inspired by early XAML presentations.)
Declarative programming goes beyond UI development. Consider Enterprise Services (formerly COM+). You can simply declare that a certain
method requires transaction support. You do not have to implement transaction support yourself, and you do not care how it works under the hood. You simply declare that you want to use it (in this case through an attribute rather than some sort of markup language).
So all of this is great and makes developers very productive. Does that mean you won't need objects anymore since they are now replaced by declarative statements? Absolutely not! I prefer to think of declarative programming as an “instantiation and invocation concept.” In the label example you are still working with objects. What you are ultimately achieving is the instantiation of the specified object as well as the setup of the desired object state. In plain imperative programming, you have great flexibility in implementing objects and their functionality. However, you have very primitive functionality when it comes to bringing these objects to life: the “new” operator, and variations thereof, such as the use of reflection in .NET. When an object is “newed” it gets instantiated in its default state. The object knows nothing about the surroundings it exists in (such as the logical location of a new label in a flow-layout Web page), nor does it know anything about how it is to be used and how it is meant to behave and appear (such as the label having a certain caption).
Of course, in the world of pure OO thought, this would not be a problem since an object would simply be instantiated and ready to go. But that is simply not a realistic assumption. In order to create a label that is completely functional upon instantiation, you could not use a default label control, but instead, you'd have to subclass it, override things such as location and text properties, and then instantiate that new label class. Then you have to repeat that action for every label you need in your application. Yikes! This would be completely unworkable. As a result, you instantiate generic label controls and set properties to make them fit your needs. But all of that is annoying overhead. It isn't challenging and it isn't fun to do. It is just plain silly and declarative programming fixes this.
What is important to realize, however, is that at the end, all you did is instantiate an object. You replaced the “new” command. Other than that, things are still the same as before, meaning that all OOP concepts still apply and are just as important as ever. The label itself still uses inheritance. It still uses methods and properties. It still uses imperative programming.
The same concept applies for the definition of a transactional component in Enterprise Services. Under the hood, someone still had to use imperative programming to create the functionality that performs the task needed for transaction support. Declarative programming simply helps us instantiate the needed components and immediately invoke a certain method (it doesn't really matter which one). This is, in fact, very similar to instantiating an object and setting a property. After all, properties really are just a pair of methods (set and get).
Note that declarative programming also has a downside. This is especially true when declarative programming is used to create UIs. Because declarative programming mainly drives object instantiation, it side-steps class-based concepts such as inheritance. When you create a new form (or any other UI component) in imperative (conventional) WinForms development, you create a new class that derives from a more basic form class. Controls that are added to that form are therefore defined in that new class, and further subclasses can be made of the whole component. It is easy, for example, to create a UI component for address entry and then subclass that component for more specific needs. In current declarative technologies, this is not possible since one only defines object instances. Therefore, no class gets created that could be subclassed. For this reason, you currently have to use imperative programming when you design for UI inheritance. This is personally a disappointment for me, and it is the reason I choose not to use declarative programming in many circumstances. Conceptually, there is nothing that prevents you from using declarative programming to define new classes. All you need to make that happen is an object-oriented compiler that supports declarative syntax in addition to conventional imperative syntax. In fact, you already get a glimpse of that in .NET today when creating strongly typed data sets, which in fact is declarative subclassing of DataSet
classes. We (that is compiler builders) just need to elaborate a bit on that concept and make it available in other scenarios.
In the relatively near future, I expect to use declarative programming in many more scenarios. Indigo will allow developers to create services and use declarative concepts around them. XAML will enable developers to do the same with UIs. However, when it comes to creating the logic for those services and behavior that goes along with the UI, I still expect to be using imperative programming for quite some time. So don't throw away that OOP book just yet…