Boost logo

Boost :

From: Kevin S. Van Horn (kevin.vanhorn_at_[hidden])
Date: 2001-10-31 13:31:30


On Tue, 30 Oct 2001 williamkempf_at_[hidden] wrote:

> --- In boost_at_y..., "Kevin S. Van Horn" <kevin.vanhorn_at_n...> wrote:
> > I'm going to go out on a limb here and say that I am increasingly
> > of the opinion that non-static member functions are usually a bad idea, as
> > they produce brittle designs and expose implementation decisions.
>
> OO experts will strongly disagree about all of this.

Of course, the priests of any religion will disagree when you challenge their
orthodoxy. Not that I'm against OO in general. It's just that I think a lot
of OO advocates go overboard and think that their particular notion of OO is
the one and only true path to programming perfection.

[I discussed Three possibilities: (1) public member function; (2) friend
function; (3) non-member, non-friend function. I stated that I prefered (3)
when possible, and lean toward (2) over (1). The reason is to limit access
to the internals of a class to only those functions really needing it.]

> In general I'd agree. However, the problem with this reasoning
> becomes appearant when the internals change making the non-member
> function implementation overly innefficient in comparison to an
> equivalent member function.

That's when you go from (3) to (2). Member functions have no performance
advantage whatsoever over friend functions.

[I discussed the problem with (1): Once a member function, always a member
function, even if in a later implementation the function doesn't need access
to the class internals.]

> I've already shown that this argument is weak. We can trivially
> change (actually, just extend) the syntax to allow for some_operation
> (x) [instead of x.some_operation()].

You miss the point entirely. Sure, you can always define a non-member
function that is just syntactic sugar on top of the member function. What
you can't do is prevent people from using the *public* member function. Once
a function is declared as a member function, there's nothing you can do to
stop library users from writing x.some_operation() instead of
some_operation(x), and hence you cannot later make some_operation() a
non-member without breaking existing client code.

> > The problem would be resolved, of course, if it were not for the
> > syntactic flaw that C++ inherited from Simula of using the awkward
> > object.function() syntax [...]
>
> Simula is hardly the only OO language that uses this syntax.

It was the first.

> You can argue that maybe the syntax isn't optimal, but it is the way it is
> and it's what OO designers expect. So the argument is pointless.

No, it's not pointless, as there will be new languages defined in the future,
and it would be well if the designers of those languages would think about
these issues instead of thoughtlessly repeating a mistake that is now decades
old.

> Templates and generic programming have lead to some slightly
> different views on design, but unless a concept is specifically meant
> to be used by generic algorithms (range may be such a concept)

I think you have this all wrong. You have to assume from the beginning that
anything might be a candidate for generalization, if not now then in the
future, and therefore one should avoid unnecessary semantic and syntactic
diversity. For example, if C++ had insisted on using different
operators for float addition, integer addition, and double addition, generic
numeric algorithms would be substantially harder to write and understand.
(I will admit that there are strong arguments for syntactically distinguishing
integer divide and floating-point divide, as there are important, necessary
semantic differences between the two.) My biggest beef against Java is the
great semantic and syntactic gulf between primitive data types and
user-defined types. This nonuniformity torpedoes any possibility of full
generic programming in Java, even if templates were added to the language, and
makes even limited generic programming very awkward and difficult.

> then I still feel strongly that it's wrong to not use standard OO designs in
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> C++,

That sounds a little dogmatic to me. I believe as strongly as anyone in the
importance of encapsulation and abstraction; I just don't have the true
believer's unquestioning faith that current OO prescriptions are necessarily
the best way of achieving those goals. Allow me to point out that the entire
field of generic programming -- and much of the current vitality of C++ --
arose because Stepanov, Musser, and others weren't willing to stick to
"standard OO designs" in the quest for generality and code reuse.

> I've yet to see an argument for the "free function" design
> that's convincing.

I've yet to see any argument that the syntactic distinction between member and
nonmember functions serves any useful purpose. As argued above, we should
strive for syntactic and syntactic uniformity as the norm, departing from it
only with good reason and to the extent necessary. The difference between a
"free function" (using friends) and member function design is purely
syntactic. From a standpoint of conceptual economy, support for generic
programming, and flexibility to grant or deny access to the innards of a
class, I prefer the uniform syntax.

> > [Proposal to avoid the need to declare private member functions in
> > public header files.]
>
> [...] employ the PIMPL idiom.

That works sometimes, but what if you want a lightweight class and don't want
to be doing dynamic memory allocation all the time?

> However, private functions don't truly
> expose implementation details, at least not to the extent that
> matters.

I'm more concerned with unnecessarily large header files and having to
recompile all source files that use a class just because I restructured the
class implementation code to factor out some common functionality.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk