Date: Wed, 04 Jun 2003 15:26:20 +0200 From: Didier Trosset-Moreau Organization: Nagravision S.A. To: accu-general@accu.org Subject: accu-general: Encapsulation issue Sender: owner-accu-general@accu.org Reply-To: accu-general@accu.org >From Didier Trosset-Moreau via accu-general list. Replies will be sent to the list (Reply-to: header set) I was wondering what was the possible use an encapsulation as follows in class A1, where the encapsulated variable can be accessed through a const and a non-const getter. class B { // whatever }; class A1 { public: B & getB() { return b; } B const & getB() const { return b; } private: B b; }; struct A2 { public: B b; }; Is there any advantage compared to class A2? I mean that when using class A1, it becomes more difficult to write and read code that calls those getter functions all throughout. Any piece of code that uses the non-const getB(), has to know about the return type, B. Exactly the same than with class A2, when accessing the public B. Furthermore, whenever the type of the private B would be changed to another type, this type will have to have at least the same interface as B (not to break code). And thus, class A1 has exactly the same constraints than class A2, where the member b is public. Can anyone tell me the reasons to write code as in A1? What do I miss? Regards, Didier -------------------------------------------------------------------------------- From: Yechiel Kimchi Subject: Re: accu-general: Encapsulation issue To: accu-general@accu.org Date: Thu, 5 Jun 2003 00:32:32 +0300 (IDT) Sender: owner-accu-general@accu.org Reply-To: accu-general@accu.org >From Yechiel Kimchi via accu-general list. Replies will be sent to the list (Reply-to: header set) > >From Didier Trosset-Moreau > class A1 > { > public: > B & getB() { return b; } > B const & getB() const { return b; } > private: > B b; > }; > > struct A2 > { > public: > B b; > }; > > Is there any advantage compared to class A2? I mean that when using > class A1, it becomes more difficult to write and read code that calls > those getter functions all throughout. > Can anyone tell me the reasons to write code as in A1? What do I miss? The following was somewhat addressed before but not as explicit as I would like it to be. No, you don't want to use _either_ one of them (unless under _very_ special circumstances). Using encapsulation is twofold: 1. Separating interface from implementation - the main benefit is seen when you really have encountered the need to modify the implementation. 2. State coherency - when attributes cannot take just any value but only a subset of possible values, usually depending on the values of other attributes (e.g, number-of-elements should reflect the actual contents of a container). Note that (2) is more important than 1, because you may be able to _prove_ that you are not going to modify implementation, and still giving direct access to an attribute will allow users to set the state of an object into an illegal state (BTW, Marshall Cline - C++ FAQs ignores this problem when he says that protected data members are acceptable within the group of developers. I don't say "never make data members protected" (except when I say it to beginners), but still M. Cline ignores this problem). [Added: following my comment, the wording of that FAQ was modified. YMK] You may conclude that the general opinion against setters (and getters) (among those who know what they are talking about ;-) stems from case (2) - it is _very_ rare that one attribute of a decent class is completely independent of other attributes on that object. OTOH, _if_ it is really a stand-alone attribute, the set/get methods will do. Nevertheless, there is another argument against set/get that is related to case (1) _even_ if _any_ value is legal. For better understanding of the class/software you want method names to reflect the _role_ of the attribute - not its type. This is why for a circle class you want to call the method setRadius() and not setInt() (because the radius type may change to double.) (I know here not every value is legal, so think about angles ;-). In the latter, however, I, personally, prefer to remove the prefix set/get and have a non-const method Radius(radius_type) and a const method Radius() with the obvious semantics. [Added May 2005: another way to look at it, as I recently presented to my students, is that set/get-ters are usually an indication of an interface that was built based on an implementation, instead of doing it the other way around - an implementation that was built to satisfy a given interface. ] Enjoy Yechiel ------------------------------------------------------------- Have you looked at recent updates to "Bad Books Amusement Park" ? Try http://www.cs.technion.ac.il/users/yechiel/CS/BadBooksC+C++.html Happy Shavu'ot (Pentecost) Yechiel M. Kimchi XXXXXXXX@xxxxxxx Faculty Comp. Sc. The Technion, Haifa, 32000 IL Office: (04) 829 4226 FAX: +(972) 4 822 1128 Homepage: http://www.cs.technion.ac.il/users/yechiel/ -------------------------------------------------------------------------------- Subject: RE: accu-general: Encapsulation issue Date: Wed, 4 Jun 2003 17:02:38 -0700 Thread-Topic: accu-general: Encapsulation issue From: "Ian Lewis" To: Sender: owner-accu-general@accu.org Reply-To: accu-general@accu.org >From "Ian Lewis" via accu-general list. Replies will be sent to the list (Reply-to: header set) I think that having getter/setter pairs indicates that your class is not actually managing its own data. This is usually a Bad Thing, but perhaps not always. I try not to use pairs of getters and setters, but I have found myself using them on classes that are essentially containers for someone else's data. For instance, one of my applications manages large branching scripts for the voice-over commentary in our sports games. I represent each node in the script with an object that knows how to load, save, and validate its data. It also knows whom to tell when its data has changed. But a large part of the class's data can be directly edited by the user, so the UI needs to both get and set it (with appropriate exception handling if the user tries to set a bad value). I'm not sure if this is poor coding, but it seems reasonable to me. Ian > -----Original Message----- > From: owner-accu-general@accu.org [...] On Behalf Of Yechiel Kimchi > Sent: Wednesday, June 04, 2003 2:33 PM > To: accu-general@accu.org > Subject: Re: accu-general: Encapsulation issue > > >From Yechiel Kimchi via accu-general list. > [Saving space: this part was removed because it appears above. Yechiel] -------------------------------------------------------------------------------- Date: Thu, 05 Jun 2003 10:38:22 +0200 From: Didier Trosset-Moreau To: accu-general@accu.org Subject: accu-general: Encapsulation issue. Ending Sender: owner-accu-general@accu.org Reply-To: accu-general@accu.org >From Didier Trosset-Moreau via accu-general list. Replies will be sent to the list (Reply-to: header set) I've found many pieces of such code in what I'm taking on right now. I often found such classes, where B is a standard library container and A usually has only one member: the b! And it simply looked to me that using A1 encapsulation in that case was useless! Thanks for all your answers. This is very interesting for all the explanations and different point of views. Regards, Didier -------- Original Message -------- Subject: accu-general: Encapsulation issue Date: Wed, 04 Jun 2003 15:26:20 +0200 From: Didier Trosset-Moreau [Saving space: The original posting was removed. Yechiel] -------------------------------------------------------------------------------- From: Adrian Fagg To: accu-general@accu.org Subject: RE: accu-general: Encapsulation issue. Ending Date: Thu, 5 Jun 2003 10:49:42 +0100 Sender: owner-accu-general@accu.org Reply-To: accu-general@accu.org >From Adrian Fagg via accu-general list. Replies will be sent to the list (Reply-to: header set) > -----Original Message----- > From: Didier Trosset-Moreau > I've found many pieces of such code in what I'm taking on > right now. I > often found such classes, where B is a standard library > container and A > usually has only one member: the b! And it simply looked to me that > using A1 encapsulation in that case was useless! Yes, of course you were right. I could imagine that the justification for that design was that each wrapping class would ensure that these containers could be passed around within classes that at least identified the meaning of the data. Suppose that you have a large body of code that works with containers of, say doubles that represent different things, e.g. Annual Sales and Quarterly Sales, then a MAT function that takes a vector of quarterly sales can't be given a vector of annual sales by mistake because it's wrapped in a different class. Note that although this argument might sound plausible, it's actually difficult to think of an example where this is actually a good design. The difficulty is that everything that I can think of would benefit from some actual encapsulation or cohesion at least. So, to take the above example, the Quarterly and Annual Sales classes would need some additional members that gave the periods of the data, this would then be begging for a better interface to access the data... Regards, Adrian Pretty pictures: http://homepage.ntlworld.com/rbyadf/