Re: Enemy Functions?
Mark Santaniello wrote:
Scott Meyers wrote an article in CUJ a few years ago entitled "How
Non-Member Functions Improve Encapsulation". Subsequently, Herb Sutter
refactored std::string using this principle:
http://www.ddj.com/dept/cpp/184401197
http://www.gotw.ca/gotw/084.htm
The basic gist is that, given a choice, we should prefer x( foo ) to
foo.x(), because the latter is less encapsulated. Scott argues that the
benefits outweigh the asymmetric syntax.
Consider two points from Scott's article:
1. From "Degrees of Encapsulation":
An easy way to measure how much code might be broken is to count the
functions that might be affected. That is, if changing one
implementation leads to more potentially broken functions than does
changing another implementation, the first implementation is less
encapsulated than the second.
2. From "Interfaces and Packaging":
Herb Sutter has explained that the "interface" to a class (roughly
speaking, the functionality provided by the class) includes the
non-member functions related to the class, and he's shown that the
name lookup rules of C++ support this meaning of "interface" [7,8].
This is wonderful news for my "non-friend non-members are better
than members" argument, because it means that the decision to make
a class-related function a non-friend non-member instead of a member
need not even change the interface to that class!
The news are not so "wonderful", as they could be: user still depends
on a whole class interface, and the interface does not change with this
trick. It's just "encapsulating" one part of class implemenation from
another part, not a real encapsulation.
Has anyone considered this before? It seems pretty obvious. Something
like this could fix std::string without breaking existing code.
But we can extract minimal interface into the base class to achieve the
same effect:
template<class charT> class __minimal_string {
public:
// minimal interface
private:
// private variables
};
template<class charT> class basic_string : __minimal_string<charT> {
public:
// fat interface
};
It helps us (1) to author these two classes and (2) to determine which
uses are either risky or rather stable. In practice, the author does
not care about the 1st benefit, or he will write such a split
implementation if he cares. From the user point of view, the member
stability is the least thing to care about: he will use the most
convenient member anyway.
There are some benefits, but there is nobody who benefits.
--
Andrei Polushin
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]