[comp.lang.c++] are 'friend's really necessary ??

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