Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Chapter 35.  Properties


35.7. Property Uses

At this point you may be thinking: nice technique, but is it anything more than syntactic sugar, with an occasional 1-byte tariff for the luxury? Well, yes and no. It is mainly syntactic nicety, although not to be discounted for that, but there are other uses for properties that have more weight, and where properties can do things that other techniques cannot. Indeed, it is the very fact that they translate semantic complexity into syntactic simplicity that can be a very powerful tool.

35.7.1 Genericity

Consider that you work with two kinds of simple rectangle structures:



struct IntRect


{


  int left, right, top, bottom;


};





struct FloatRect


{


  double left, right, top, bottom;


};



You may use several complex templates to work with these structures, whose implementations rely on the public accessibility of the fields left, right, top, and bottom. Now you need to define a class that notionally represents a rectangle, but whose coordinates are defined in a different manner, perhaps as the two points top-left and bottom-right, or whose values are only obtainable via a method call. In this case, you would need to rewrite your algorithms, either to use traits or shims (see Chapter 20). But they may not be your templates, or the potential for introducing error into them is just too risky at your stage in the project. Either way, it can represent an unattractive amount of effort, and you need a much quicker solution. One alternative is to use properties. Simply enhance your new rectangle, say DynRect, type, and give it left, right, top and bottom properties.



class DynRect


{


  . . .


  union


  {





    METHOD_PROPERTY_GET_EXTERNAL_PROP(int, DynRect, get_left, left);


    METHOD_PROPERTY_GET_EXTERNAL_PROP(   . . . // right, top, bottom


};


  . . .


};



Even if you have to use external properties, and paying the 1-byte space cost is not justifiable in the long run, you have a robust and, except for a potential additional memory cost, efficient short-term solution to take you past your next milestone. (Of course, this being the real world, you then run the risk of it never being retro-optimized, but maybe a successful suboptimal product is the best of the alternatives open to your company at that time.)

35.7.2 Type Substitution for Diagnostics

As a diagnostic measure, consider the case where you have a lot of legacy code that uses struct tm and that there are occasional date/time errors cropping up in your testing. It would not be hard to create your own tm-like type, where the "fields" are replaced by validating properties (see Listing 35.32), and then to plug this into your existing code.

Listing 35.32.


class tm_spy


{


  . . .


  method_property_getset_external<int, int


                                , tm_spy


                                , &sec_offset


                                , &get_sec


                                , &set_sec


                                >                     tm_sec;


  . . .


  method_property_getset_external<int, yday


                                , tm_spy


                                , &yday_offset


                                , &get_yday


                                , &set_yday


                                >                     tm_yday;


};



If it's your source, then all you'll have to do is make a single typedef change in a root header, right? However, even if it's someone else's code, and struct tm is dotted all around the place, you've several tractable, though not pretty, options. You could do a global search and replace to a single common typedef. This would probably be a nice idea anyway, since it would break nothing, and would facilitate any future changes with ease. Alternatively, you can define your class as a struct, and then #define tm tm_spy. Hokey stuff, indeed, but we're talking about diagnostics, rather than production code.

Anyway, I digress. The point is that once you've got your new type plugged in, you can run up the offending application, and your "smart" struct tm can detect any erroneous date manipulations. What you do when you catch them—logging to a file, printing to stderr, tHRowing an exception, assert()—is up to you. Thus, even in the cases where external properties are not the development solution due to their space inefficiency, they represent a useful diagnostic tool.

Alternatively, you may have a more benign requirement, which is simply to instrument the modifications to your structure. Again, properties can be the answer: just implement the write methods to log the activity.


      Previous section   Next section