Grokking properties

It's one thing to know about properties and another to genuinely own the concept and understand its usefulness.

You can't program in Delphi without using properties. They're everywhere. Open the Object Inspector, and you see a Properties tab. Go to the Delphi help file, and every component has its list of properties. Write code and there's a good chance you'll type property names. But are you sure you fully grasp how properties work? Do you appreciate their power? Do you use properties effectively? If you can answer those questions with a yes, then read no further. But I've discovered from e-mail, newsgroups, and conversations that few Delphi programmers can.

Encapsulation to the max

Object Pascal properties are an extension of the encapsulation model provided by classes in most object-oriented languages. Object-oriented purists argue that methods should be public while data fields should always be private, to which many programmers reply: "What about the extra code? It's boring to write and slows performance when you're simply reading or setting a value." 

The properties in Object Pascal are a powerful solution to this dilemma. You declare a public (or published) property and map it to a private field or an access method. If you're mapping directly to a field there is no extra code to write and no performance drawback over using a public field. However, the encapsulation rule is fully preserved: The user of the component doesn't need to know how the property is implemented and the component writer is free to change the implementation. In fact, even if you change the property mapping to use an access method, all you need to do is recompile the code.

The component writer can also change the storage structure for the property and the internal data type. Many properties don't even map to data fields. For example, one of the most common Delphi properties, Caption, is not saved by components as an internal string. Instead, it's sent to the corresponding Windows API function to change the window text. The reverse operation is executed when you retrieve the component's caption.

Delphi properties are different from the corresponding concepts in Java Beans and COM. In those component models, properties are always resolved by methods. The convention in Java is to use set and get methods with the property name. (Despite this and other differences, the Java Beans component model was inspired in many areas by the VCL.)

More than a language feature

Properties are not only part of the language, they're also supported in the Delphi IDE and runtime system.

In Delphi, properties are often used in conjunction with run-time type information. When you declare the properties as published, the compiler generates internal type information structures. These structures are used mainly by the visual support and streaming systems. You can directly access this information using the data structures and routines available in the TypInfo unit. 

Published properties define the persistent state of an object. Using the Object Inspector in the Delphi environment or your own tools, you can set the initial values for the properties of an object. These are later saved in a DFM file and then included in the executable file, ready to be reloaded when the object is created. To be more precise, the DFM file contains all the information required to create the components and restore them to their initial state.

I call this "persistent" to contrast with the runtime state of a component, which often includes extra dynamic data. Part of a component's startup state is determined at runtime by the program and operating system. An obvious example is the Handle of a windowed control, which is reassigned every time by the OS.

It's important to note that by streaming an object, Delphi doesn't save its internal structure and doesn't dump the object memory to disk. That would be useless because an object often contains references to internal objects and strings that use separate memory areas. Instead of saving the object data structure, the streaming system works by querying objects for the value of each property of their published interfaces. 

Delphi's streaming system is quite elaborate and provides for default property values, which are not saved, and  special streaming conditions (indicated by the stored keyword). It also handles other special cases, including extra non property-based values that a component can save by overriding the DefineProperties method.

But that's not all

Properties provide additional features. I mentioned the new dynamic property access function available in Delphi 5 in my last article. Another important trick is enhancing array properties, which are based on an index you indicate within square brackets. The index is often numeric but can also be based on other data types. The Table component uses a default property based on strings -- the names of the table's fields. An array property of a component can now be set as the default, which is a nice shortcut. You can omit the property name and apply the square brackets to the original component:

TableCountry ['Capital'] := "Rome"

instead of:

TableCountry.Cities ['Capital'] := "Rome"

This is a typing shortcut. I think it is also the closest thing to an overloaded operator in Object Pascal!

One last question

Is Ctrl-Shift-C a regular part of your keyboard repertoire? The answer provides much insight into your use of properties. The key combination invokes the Class Completion feature and makes property use a breeze. Whenever you are about to add a global variable, type the property keyword, press Ctrl-Shift-C, and you're in the property business. 

Properties are one of the key elements of Delphi's architecture and of its success. No other visual environment shares this powerful and flexible feature -- not even the one with more programmers.

Queries about lost property may be addressed to me.

Originally written for InPublishing LLC for publication by Inprise Corp. Copyright 1999 Inprise Corp.