herman@kulcs.uucp (Herman Moons) (03/17/90)
I don't know whether this question appeared earlier on the net.
Are there any *good* reasons for having the friend concept in C++ ?
The example given in Lippman's book:
class Screen;
Screen myScreen;
cout << myScreen; // friend needed to implement this
does not seem convincing. The friend mechanism is used in this case to
circumvent a bad design choice. After all, << is an operator defined in
the stream classes, while outputting an object logically belongs to the
object itself (you say to the object: output yourself).
Wouldn't it be better to say:
class Screen {
ostream& operator>>= (ostream& out); // no friend needed here
};
myScreen >>= cout;
yourScreen >>= myScreen >>= cout;
Discussions with my colleagues didn't provide an example were friends were
really necessary. We could always find ways to implement our classes such
that the information hiding principle wasn't violated. We also couldn't
find a good example where data abstraction resulted in a serious loss of
efficiency (we could always find sensible inline functions that provided
fast access to the needed information).
So, if you have an example that really proves the necessity of the friend
mechanism, please post it. After all, if there is no real necessity, the
mechanism is just an unnessary loophole in the language to defeat the
information hiding principle.
-----------------------------------------------------------------------------
Herman Moons Katholieke Universiteit Leuven
Dept. of Computer Science
Tf : +32 (16) 20.06.56 Celestijnenlaan 200A
Fax: +32 (16) 20.53.08 B-3030 Heverlee-Leuven
Belgium
e-mail: herman@kulcs.uucp
herman@blekul60.bitnet
herman@cs.kuleuven.ac.be
-----------------------------------------------------------------------------
shiffman@basselope.Sun.COM (Hank Shiffman) (03/17/90)
In article <169@pollux.kulcs.uucp> herman@kulcs.UUCP () writes: > >I don't know whether this question appeared earlier on the net. >Are there any *good* reasons for having the friend concept in C++ ? > >Discussions with my colleagues didn't provide an example were friends were >really necessary. We could always find ways to implement our classes such >that the information hiding principle wasn't violated. We also couldn't >find a good example where data abstraction resulted in a serious loss of >efficiency (we could always find sensible inline functions that provided >fast access to the needed information). > >So, if you have an example that really proves the necessity of the friend >mechanism, please post it. After all, if there is no real necessity, the >mechanism is just an unnessary loophole in the language to defeat the >information hiding principle. > One case where friend functions are appropriate is where we may get to the function via typecasting. For example, let's say we implement a ratio class. We have a constructor for a ratio which takes zero, one or two integers. Now we want to implement subtraction. We might use a member function: ratio operator- (ratio&); or a friend function: friend ratio operator- (ratio&, ratio&); We choose to implement using a member function. Now consider the following piece of code: main () { ratio a(1,2), b, c; b = a - 5; c = 27 - b; } When compiling "b = a - 5", C++ won't find a function which subtracts an int from a ratio. However, there *is* a way to cast the int to a ratio (the ratio constructor), so the operator- member function can do the subtraction. Now consider "c = 27 - b". We can't use the member function, since C++ won't cast the recipient of the operator- "message". We *could* recode this as "c = -b + 27", assuming that we've defined the unary minus, but that's not fair to the user of our class. If we implement operator- as a friend function, then C++ can cast either one of the arguments to the ratio type and perform the subtraction. The requirement that the target of the member function be in the first position creates the need for friend functions. BTW, Dewhurst & Stark's Programming In C++ has a good explanation of this issue in relation to a complex number example.
ark@alice.UUCP (Andrew Koenig) (03/17/90)
In article <169@pollux.kulcs.uucp>, herman@kulcs.uucp (Herman Moons) writes: > I don't know whether this question appeared earlier on the net. > Are there any *good* reasons for having the friend concept in C++ ? Sure. One of the most common is when you're writing several interrelated classes. > The example given in Lippman's book: > class Screen; > Screen myScreen; > cout << myScreen; // friend needed to implement this > does not seem convincing. The friend mechanism is used in this case to > circumvent a bad design choice. It is at least as bad a design choice to require myScreen >>= cout; but to allow cout << "hello world\n"; The inconsistent syntax does nothing to help program clarity. I will admit, however that it is possible to write this particular example without friends: class MyScreen { // ... public: ostream& print(ostream& o) { // print *this on o return o; }; }; ostream& operator<<(ostream& o, const Screen& s) { return s.print(o); } The operator<< defined here does not need to be a friend of MyScreen as long as the print function is public. Of course you may not want the print function to be public. After all, there's no overriding reason to fix it as part of the interfact to MyScreen. But if you make it private, then operator<< must be a friend of MyScreen... -- --Andrew Koenig ark@europa.att.com
coggins@rhodopsin.cs.unc.edu (Dr. James Coggins) (03/18/90)
In reply to the subject question, "No, but there are good reasons for having them." I don't like the friend examples where the reason for friend-ing is to permit commutative usage of operators. That strikes me as a syntactic cure for certain kinds of laziness, but on the other hand, such cures can sure be useful. A better example of friend classes arises in my COOL library where I have two classes that are separated for the purpose of isolating some highly changeable junk from the main class definition, which is pretty clean and understandable. I make the classes friends and create the junk class object in the constructor of the good class, providing a pointer to the good object so the junk object knows what good object it is associated with. That's the only pair of friend classes in my library, and I have no friend functions at all. --------------------------------------------------------------------- Dr. James M. Coggins coggins@cs.unc.edu Computer Science Department Questions: "How 'bout them HEELS?" UNC-Chapel Hill Correct response: Chapel Hill, NC 27599-3175 "How 'BOUT them Heels?" and NASA Center of Excellence in Space Data and Information Science ---------------------------------------------------------------------
ruud@targon.UUCP (Ruud Harmsen) (03/19/90)
In article <10589@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes: >In article <169@pollux.kulcs.uucp>, herman@kulcs.uucp (Herman Moons) writes: > >> I don't know whether this question appeared earlier on the net. >> Are there any *good* reasons for having the friend concept in C++ ? > >Sure. One of the most common is when you're writing several >interrelated classes. > Only too true. And isn't this also the fundamental weakness of the object oriented concept? For in the real world, and so in any realistic information system describing a part of that real world, *nearly all* classes are interrelated to *nearly all* other classes. Classes often only make sense just because of their relations to other classes. So if you have to use friends for that, everyone will be anybody's friend, and as a result of all this friendship, a *real* project in an OO-language tends to become just the same mess as it does in a traditional language, like C. (Note: I admit I don't have experience with OOT, but only more so with complicated applications).
sakkinen@tukki.jyu.fi (Markku Sakkinen) (03/20/90)
In article <1082@targon.UUCP> ruud@targon.UUCP (Ruud Harmsen) writes: >In article <10589@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes: >>In article <169@pollux.kulcs.uucp>, herman@kulcs.uucp (Herman Moons) writes: >> >>> I don't know whether this question appeared earlier on the net. >>> Are there any *good* reasons for having the friend concept in C++ ? >> >>Sure. One of the most common is when you're writing several >>interrelated classes. >> > >Only too true. And isn't this also the fundamental weakness of the object >oriented concept? For in the real world, and so in any realistic >information system describing a part of that real world, *nearly all* >classes are interrelated to *nearly all* other classes. [...] > ... Here seems to be some misunderstanding - Koenig should probably have written "_tightly_ interrelating". A given class need generally be _directly_ interrelated only to relatively few other classes, which we could call its acquaintances. In most cases, the communication between acquaintances needs to use only public operations (and data). Sometimes however, there is a real need for a closer cooperation between some classes (without any inheritance relationship between them). That's what friend declarations are good for. Ada and Modula-2 have the advantage over almost all OO languages that really tightly interrelated types can be defined within the same package or module. Certainly both this facility and the friend concept of C++ can be easily misused also. Markku Sakkinen Department of Computer Science University of Jyvaskyla (a's with umlauts) Seminaarinkatu 15 SF-40100 Jyvaskyla (umlauts again) Finland SAKKINEN@FINJYU.bitnet (alternative network address)
reg@ksr.UUCP (Rick Genter) (03/20/90)
In article <1082@targon.UUCP> ruud@targon.UUCP (Ruud Harmsen) writes: >In article <10589@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes: >>In article <169@pollux.kulcs.uucp>, herman@kulcs.uucp (Herman Moons) writes: >> >>> I don't know whether this question appeared earlier on the net. >>> Are there any *good* reasons for having the friend concept in C++ ? >> >>Sure. One of the most common is when you're writing several >>interrelated classes. >> > >Only too true. And isn't this also the fundamental weakness of the object >oriented concept? For in the real world, and so in any realistic >information system describing a part of that real world, *nearly all* >classes are interrelated to *nearly all* other classes. Classes often only >make sense just because of their relations to other classes. >So if you have to use friends for that, everyone will be anybody's friend, >and as a result of all this friendship, a *real* project in an OO-language >tends to become just the same mess as it does in a traditional language, >like C. > >(Note: I admit I don't have experience with OOT, but only more so >with complicated applications). As one who does have experience with OOT and with complicated applications, I (unfortunately) have to agree with the gist of this assessment. There are classes of applications where OOT is wonderful. User interface is one. Discrete simulation is another. But how about a globally-optimizing incremental compiler? Or an operating system? Actually, operating systems have potential; there are lots of "independent" objects that have well defined behaviors (e.g., processes, threads, files, users :-), but then there is all the other "cruft." Is a protocol an object? If not, how does it fit in to an OO OS? Note that these can be made to work, but at a significant performance penalty. The penalty is not the penalty of a single virtual method invocation vs. a single function call; I grant that that is (usually) insignficant. But often what happens is that a method will invoke several other methods, each of which will invoke other methods, and so on and so on. Suddenly that insignificant overhead becomes quite significant. It seems to me that a study needs to be performed not on how to make everything OO, but on how to make composite designs work: i.e., how do I easily integrate my OO UI with my procedural data-flow analysis. - reg
mcconnel@p.cs.uiuc.edu (03/23/90)
reg@ksr.UUCP says: > There are classes of applications where OOT is wonderful. User interface is > one. Discrete simulation is another. But how about a globally-optimizing > incremental compiler? Or an operating system? As it happens, the group I'm in is working on a globally optimizing incremental compiler (for Smalltalk and written in Smalltalk). We have class hierarchies representing various kinds of flow nodes, register transfers, machine instructions, etc. OOT has served us quite well in describing these objects. Carl McConnell Department of Computer Science University of Illinois at Urbana-Champaign INTERNET: mcconnel@cs.uiuc.edu UUCP: {uunet|convex|pur-ee}!uiucdcs!mcconnel BITNET: mcconnel%cs.uiuc.edu@uiucvmd