C. Keith Ray

C. Keith Ray is developing software for Sizeography and Upstart Technology. He writes code for multiple platforms and languages, including iOS® and Macintosh®.
Go to Sizeography and Upstart Technology to join our mailing lists and see more about our products. Keith's Résumé (pdf)

Sunday, November 17, 2013

More on Reset, Encapsulation, Value and Immutable Objects

(Originally posted 2003.Apr.19 Sat; links may have expired.)

A reader suggests that I could use reference counted smart pointers to avoid problems I described previously.

That would not fix the problem of violating encapsulation -- retaining one object's member data in multiple other objects. In fact, in this application, if we were using boost::shared_ptr or our own reference counted smart pointer, and did the 'delete'/'new' approach, the result would be multiple "platform independent document objects" in a program designed to have only one document object. The various distinct views of the document would get out of synch. (I do use boost::shared_ptr in my application, to enable passing around large image objects among image processing functions as if they were Value objects -- I don't have to worry about premature deallocation.)

The same reader suggests that a Reset method isn't that bad... He writes "Functional requirements for cleaning self up logically belong in the object, not in delete/new."

I would say that in C++, the requirement for an object cleaning self up belongs in the destructor, by definition of "destructor". Whether the coder does the same cleaning up in Reset is up to the coder.
Probably the real reason for my dislike of Reset is that some coders using it seem to have confused "variables" with "objects". You reset a variable. You create and delete objects. In the application I was talking about, the object has effectively become a global variable, with all the problems that globals have, even though only member variables are being used.

In some ways it is even worse, because these variables are actually pointers to a global object: those pointers can become dangling pointers if the object is deleted by what is supposed to be its sole owner. Using Reset hides the fact that this is a global... better to make it a real global variable, to avoid the dangling pointer problem, or not pass it around at all (which is what LoD recommends). The application I was describing is a single-document application, so the MFC document object is effectively a global variable/global object.

My other point about Reset is that Value objects don't need it, and Immutable objects can't have it.
Imagine a Dimension object. In Java or Smalltalk, you might want to make it immutable, so you can safely return Dimension member values without making copies. This assumes that you don't do lots of math on Dimension objects -- because that would require making copies. It is a choice of which is more efficient, and/or safer.

In C++, I would implement Dimension as a Value object - one that implements the copy constructor and the assignment operator (and default constructor for STL compatibility). Returning this kind of object "by value" automatically makes a copy. If you want to reset a Dimension variable, just assign Dimension(0,0) to that variable. You minimize the number of methods to write, and you make it very clear what you're doing.

Keith Ray is developing new applications for iOS® and Macintosh®.. Go to Sizeography and Upstart Technology to join our mailing lists and see more about our products.

No comments:

Post a Comment