Python is wierd!

Mark Baker mbaker at 0x7a69.net
Thu Jul 27 00:58:47 EDT 2000


In article <8lnrpk0qoc at news1.newsguy.com>, "Alex Martelli"
<alex at magenta.com> wrote:
> "Mark Baker" <mbaker at 0x7a69.net> wrote in message
> news:SQGf5.5281$c04.627774 at nntp2.onemain.com...
>     [snip]
>> >> friend is simply an evil way of violating encapsulation. It's not
>> > analogous to
>> >
>> > Absolutely false, although people with a superficial understanding of
>> > C++ do tend to think that way.  The proper use of 'friend' is to
>> > split an encapsulated, cohesive functionality among more than one
>> > class,
>> > *because the class is NOT the natural unit of encapsulation*.  friend
>     [snip]
>> I've been writing in C++ for many years now, but this isn't a matter of
>> who has a larger penis...
> 
> Clearly not: it is a matter of who is right, and who is wrong, about a
> specific technical issue: is "friend", in C++, "simply an evil way of
> violating encapsulation", as you say, or is it rather a way to correctly
> partition the functionality of one component among more than one class,
> as I say?

Firstly, let me apologize for not doing an entire line-by-line analysis of
everything you've said. This post is most large, and I simply do not have
the willpower to cover each and every one of your blocks, especially when
you take so much of my context in a purely C++ light. If you care to "win"
that much, telle est la vie. ;-) Consider this elaboration and context
determination. I will try to touch a bit on your important statements, if
possible.

I think, perhaps, I unintentionally downplayed my reference of other
languages in terms of looking at the decisions of C++, like friend. I am
looking at friend not from within C++, but from within an abstract view of
what it does. If you would like me to specialize on a strict languages,
then I will, but friend is still broken. I'll not specialize on C++
entirely, since other languages provide this functionality better.

friend is practical for many things in C++, especially given  its
framework. It's most useful in containers, as you mentioned.

I would call friend evil, and consider it an encapsulation violation. For
a strict language, you might expect some sort of coupling that violates
encapsulation a little, friend is a bit like a hammer. Friend should not
be necessary in an elegant language or design, but what is good is
relative. If you want the feeling of safety provided by extended
encapsulation concepts, Modula, Oberon, and Eiffel might be good. If
you're only concerned with a certain amount of safety, Dylan is good.
These languages are a bit wordy, syntax-wise, but their feature and design
sets are good. Otherwise Smalltalk and Python are excellent. This is all
my biased opinion, however, and detracts a bit from friend. ;-)

It's also misused (of course this can be said for many features of many
languages... this was a minor sub-point...consider it dropped).

However, "encapsulation" exists independently of any one language. This,
perhaps, becomes a problem when languages take their own concepts of
encapsulation. For me, the unit of encapsulation is the object. Whether
this displays itself at a class level (assuming the language has
classes...) is relative.

If you enjoy calling a series of coupled classes a component, alright. If
you'd like to move encapsulation away from an object and instead attribute
it to a collection of classes, ok.

In the context of requiring some form of coupling between classes, but not
at a level of seeing a series of classes as a "component" let me comment a
little on friend...

Do you think it violates encapsulation to allow unfettered access to a
class's content? I surmise not, provided that you're refering to coupled
classes or specific functions outside of a class.

Would you suggest that this is safe to provide access to the contents,
without any interface constraints? That is, being able to manipulate
instances, instead of just access private methods?

Would you consider it better to provide fine grained access? That is,
access to specific portions of a class, than to allow unrestrained access?
Or do you think that because this isn't a violation to couple a
class/function, that such granularity is unnecessary? Would this possibley
lead to more correct code in your opinion?

Have you ever used Eiffel? Perhaps you've seen a snippet like

feature { ACLASS }
	blah(stuff : INTEGER) is
		do
			something := stuff
		done

Would you still consider friend a needless violation, seeing this
constraint? If the goal is safety, is 'friend' not evil in comparison?

> As it happens, one B. Stroustrup appears to share this opinion, in as
> much as he wrote, for example, in the Annotated C++ Reference Manual, "A
> friend is as much a part of the interface of a class as a member is". 
> Saying that friends are evil and break encapsulation is therefore just
> about as silly as saying that member functions do so; they are BOTH
> parts of the class's interface, so why single out one over the other as
> "evil" &c?

A public method is a specified interface for an object. Using an object's
interface doesn't allow it to access implementation and private
information.

Allowing a class or function 'friend' status allows it intimate access to
the contents of an object. Taking the stance that another class is
entirely part of another class, and considering this 'safe' is silly. If
you take the stance that you need to strictly restrict access to a class,
you must also mean coupled access as well.

I don't imagine that you would utilize implementation details where they
are unecessary within the class itself, to promote safety, since you claim
to be such a good designer and especially C++ programmer. You do not trust
the programmer, nor the class instances themselves to rely on the
implementation. So why exactly would you give total access to your class
from a foriegn class? Because you couple them and call it a component? Why
is a coupled class given access to methods it won't use?

 
> How do you propose that the component's semantics, "every
> 'creation' of X MUST occur through a call to Factory's
> methods, every 'destruction' of X MUST occur through yet another set of
> such methods", be enforced "by the accessor/mutator pattern"?  I'll tell
> you: *YOU DON'T*.

Depending the design intent, you could simply use a static factory. Do
request-based caching, and allocate when necessary. All without using
friend.

Or you could listen to your voice inside screaming for reusability, and
provide the factory system as an alternative allocation system, instead of
creating this required constraint. I don't see you doing this, though,
given your reply. ;-)

If you really must fall upon a coupled class, then 'friend', as I've
pointed out above, has been done better. Better than to grant access to
every method, than just those required for allocation/deallocation.

> C++'s approach to encapsulation has its limits, but
> "friend" is DEFINITELY not such a "limit": it is a

Yes, in fact, it is. Even if you wish to look at it from a strict language
perspective. It's been done better.

> crucial ingredient of good large-scale C++ software design.  Have you
> never met such issues in your "many years" of C++ experience?!  Or have
> you let your fetish for letting the class play the inappropriate role of
> unit of encapsulation stand in the way of good design, when faced with
> such issues?  Perhaps not noticing the fact that friends *are* a part of
> a class's interface...?

You've won my "arrogant self-righteous presumptious" argument of the day
award. Good job. Try to be more condescending next time.

Yes, I've used friend in my C++ programming career. I still see that it is
bad in the context of software design, both in terms of strict and and
non-strict

The object, as I said, is my unit of encapsulating an object. If a
language is sufficiently restrictive/broken, this will be violated in any
number of ways. I don't have to 1) like it 2) consider it good design.


>> Friends, if attempted for use as "encapsulation" suffer from issues
> regarding
>> protecting implementation details, in a paradoxial and limitedly
> extendable way.
>> It is rare to be used in this manner.
> 
> Well-designed software is rare.  In well-designed C++ software, however,
> the proper use of 'friend' is QUITE frequent, and suffers from none of
> the ills you claim for it.

I've seen very little well designed software in C++. Some of the better
and open source work are of the quality of things like libsigc++. This
uses friend for a bit of its reference system.

I would not call the use of friend frequent. Where it's used, a more
constrained system would be better.

>> In the real world, people do use friend to violate encapsulation.
> 
> In the real world, there's a lot of horribly designed code, and a lot of
> people who do not understand a too-complex tool well even if they have
> been using it for years.  C++ is arguably too complex for most
> programmers who now use it, and for most uses to which it is put;
> Python's simplicity and straightforwardness are a deep breath of fresh
> air, in comparison, even to somebody who's easily in the top centile in
> terms of knowledge of C++'s arcana.

You can't attribute all of the bad C++ code to its poor design (which lead
to its complexity). A lot of the design issues of C++ projects would still
exist, even if it weren't written written in C++. This is because many
people are either poorly educated in software engineering, or simply not
suited for job of analysis and design.

Of course C++ does lead to some interesting results, such as people that
feel they can't function in a less restrictive shell, people that find
non-C++-like syntax horrible, people that move to other languages and
attempt to program as if they're still using C++, people that are obsessed
with the performance of every line of their software, and people that fail
to ever look back and say 'Wow, that was messed up. I can actually reuse
my code now," or "You mean the language will actually provide real static
typing, and help to ensure its reliability?"

 
> But that does not justify insulting those language features one does not
> understand, rather than either trying to understand them better, or
> giving up the language altogether.
 
How naive to assume I don't understand friend, because I don't like it. I
mention its direct place of common misuse by others (in my experience),
and you assume I've never used friend elsewhere. Tsk tsk. Perhaps, I
should suggest that you shouldn't attempt to play apologist to language
features, when you're ignorant of where they're done better, or why the
problem domain they met is moot. I won't though. I'll simply assume you
prefer things they way they are, and don't think that other methods of
design are better. Even more naive is the assumption that I would "give
up," a language simply because it's not perfect.

Perhaps I'm taking your commentary too seriously, but I find it insulting
that you continually imply my inability to comprehend such a simple
language concept, simply because I've a broad range of experience with
other, more productive concepts.

This discussion has honestly gone on too far, and I don't imagine it
belongs here. comp.lang.misc or comp.lang.c++ seem much better candidates,
but I've no intentions of carrying it further. If you would like be to
clarify more (I was rather vague, before), you can e-mail me and I'll be
more than happy to wax philisophical over C++.

I apologize for creating this line of noise on the newsgroup. Next time
I'll prefix my 'friend' commentary with a ;-) so the C++ zealots won't
send the napalm my way. =P




More information about the Python-list mailing list