On Properties in C Plus Plus

From StoneHome

For a long time I've been pretty torn on the issue of properties in C++. On the one hand, in Delphi where I first learned them, they're hella convenient. They allow for a sort of conceptual abstraction between functions and variables that a lot of people are very bothered by at first (among whom I can count myself.) "Getters and setters are jus' fine." Etc.

I'm going to go out on a limb to justify why properties are good conceptually, first. Then I'll get into their practical implementation and implementation issues. Finally, I'm gonna do some complaining like usual.

Thing is, we're often admonished that objects aren't classes, that they're UDTs. If one chooses to adhere to the viewpoint of making classes to represent types - which C++ has done wholeheartedly through syntactic sugar like operator overloading - then one has already ceded that functional definition should be allowed to step in when concrete behavior is expected.

UDTs have their operators overloaded not only for convenience. The algorithms in the STL could have worked just as easily with .lessThan() instead of ::< . Thing is, that could have worked just as well in C, and it took a long time after other languages exhibited UDTs before someone wrote C With Classes. There's a certain importance to treating your types in the same way that you treat machine types; it allows one to accept that there's no practical difference between int and CInteger at the conceptual level.

Another less obvious fundamental shift occurred in C99, with the introduction of the Complex type. Things held as simple types conceptually, such as mathematical primitives, are beginning to be allowed to have members. This isn't as disconnected an issue as it first sounds. When one wants to implement a UDT to simulate a primitive - say, an integer larger than the host platform's native limits, or an arbitrary precision real - then it's important to be able to work with the faux primitive as you're used to, rather than writing C reminiscent of LISP, which is distracting in a C context and difficult for people not used to both paradigms.

If complex may have POD members, then when we implement arbitrary-precision float complex, we're going to want to be able to present the data members from functions. Conceptually, properties are the conceptual analogue of data members that operator overloading is to expressions. Many creation-oriented patterns and idioms make the same analogue for allocation owing to more complex functional behavior, such as abstract factories, flyweights, pooling and re-use mechanisms, and compositors. It is arguable that this is the general behavior of containers, though in C++ a more powerful mechanism for containers (templates) has since supplanted them; however, some old codgers may remember the days of generic stacks and vectors and so forth passing void pointers willy-nilly (in this respect, MFC is an archaeological treasure trove.)

I'll try to keep my discussion of OOP short. I believe that properties fundamentally support encapsulation. A simple but potent example is adapting to changing requirements.

Comeback: write examples of resources across the network, supporting legacy code

Another more complex example is that of the data driven machine.

Comeback: the data driven machine gets ridiculously powerful if the data can change; suddenly it's a virtual machine of sorts. Compare a MIX machine to a data-driven machine. Compare to classes versus structs. Show how properties can be used to implement machines in systems which were originally just functions.

'Course, this is a dangerous one. Much like threads threw state-safe data access into the spotlight and classes threw mutability and const correctness into the spotlight, a data driven machine with dynamic data is going to show off some very nasty problems with volatility correctness, and legacy stuff may occasionally choke due to volatility errors and caching assumptions which at first aren't well understood, but hey, that's

talk about language-based implementations. when they're good enough, when they aren't. template-based policies. assert as a macro-based rudimentary contract system. show a property class implemented by operator(), then show larne's property template. talk about c-with-classes, and all the optimizations it couldn't make that modern compilers now make. talk about the important difference between a library mechanism and a language mechanism. talk about type safety; equate properties to telling the compiler things by establishing class-based type identification systems, const/volatility correctness, inline and register, that sort of thing. The more your compiler knows the more optimizations it can make safely. Being able to substitute functions for simple values in some classes but actual values in others would allow the compiler to make lots of optimizations when a concrete class was known but not others when the type wasn't. blah blah blah.
show in the end, we'll only pay for the function overhead when it's actually used, with some optimization along the lines of the zero table optimization or the nrvo, some fancy-pants realizing that there's some crafty way for the compiler to realize when the overhead is useless and optimize it away.