Path: utzoo!attcan!uunet!husc6!uwvax!umn-d-ub!nic.MR.NET!uwmcsd1!leah!bingvaxu!sunybcs!oswego!rocky.oswego.edu!dl From: dl@rocky.oswego.edu (Doug Lea) Newsgroups: comp.lang.c++ Subject: Re: Friend specifier considered harmful Message-ID: <931@oswego.Oswego.EDU> Date: 16 Sep 88 13:24:42 GMT References: <29433@bbn.COM> <8180@alice.UUCP> <311@sdti.UUCP> Sender: news@oswego.Oswego.EDU Reply-To: dl@rocky.oswego.edu.UUCP (Doug Lea) Organization: SUNY, Collego at Oswego Lines: 74 Even in object oriented programming methodologies, there is plenty of room for `pure' constructive functions (i.e., functions that construct a new object based on some unaltered, possibly `private', properties of their arguments), as opposed to non-constructive, potentially `mutative' member functions that change and/or report state. Such functions must often be declared as friends. Consider, for example, a numerical class `Num', with instance `n', and two supplied routines: n.abs(); A member `mutator' routine that replaces n with its absolute value (probably returning *this by reference) and Num y = abs(n) A friend `constructive' function that returns a new object that is the absolute value of n, without changing n. Similarly, with a class `List' and instance `l': l.reverse() Reverses l in-place and reverse(l); Returns a new List that is the reverse of l. From an object-oriented view, pure constructive functions like abs(n) and reverse(l) are on the same par as class constructors themselves: Both `List(l);' (via the X(X&) constructor) and `reverse(l)' construct new objects using essentially the same logic, and requiring the same internal data access privilages. One could dispense with the above functional forms, and force clients to create reversed objects via `List y(l); y.reverse()', but why should clients be required to use a construct that is both less natural and less efficient (clearly, `reverse(l)' could be implemented significantly more efficiently that first constructing then reversing.) Of course, it is not always necessary to support both constructive and mutative versions of everything, but there are cases where support of both versions makes sense, and yet more cases where only the constructive version is desirable. I tend to use friend functions in these situations. Any class I write that ought to support a number of constructive functions, but otherwise must promise to maintain internal integrity of its private data (as with numeric and list types) has many friend functions. The alternative of supporting public low-level data access facilities (that would enable these to be declared without `friend' status) opens up the class to far more potential abuse than does the implementation of a fairly complete set of constructive friend functions, without any other access provisions. Another alternative of implementing two member functions, functional l.build_reverse() and mutative l.self_reverse() does not seem attractive either. Pure functions ought to possess functional notation, and member functions should almost always be just those that mutate and/or report state. This sort of function-versus-member distinction is already blurred a bit in C++, since both constructive and mutative versions of operators (e.g., `+' vs. `+=') may be declared either as friends or as members. (I declare the mutative operators as members and the others as friends -- As a further aside, I find that I am almost always dissatisfied with any C++ routine that *both* mutates and constructs.) Part of the dispute about the use of `friend' functions is based upon the fact that `friend' does not exactly mean `intrinsic' (i.e., logically a part of a class), as perhaps it should in these cases. Several ways to modify C++ to behave in this fashion come to mind. One possibility would be to allow `reverse(l)' to somehow be given the same status as a constructor (i.e., to allow constructors to have different names than the class name). Any solution should allow such functions to be virtual, inherited, etc. In the mean time, using `friends' seems the most practical way to handle this. -Doug Lea Doug Lea, Computer Science Dept., SUNY Oswego, Oswego, NY, 13126 (315)341-2367 email: dl@rocky.oswego.edu or dl%rocky.oswego.edu@nisc.nyser.net UUCP :...cornell!devvax!oswego!dl or ...rutgers!sunybcs!oswego!dl