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.
|