Required Reading: "How Non-Member Functions Improve Encapsulation"

Jonathan M Davis newsgroup.d at jmdavisprog.com
Thu Oct 26 22:05:22 UTC 2017


On Thursday, October 26, 2017 12:53:38 JN via Digitalmars-d wrote:
> On Wednesday, 25 October 2017 at 22:19:23 UTC, Walter Bright
>
> wrote:
> > for core D devs.
> >
> > "How Non-Member Functions Improve Encapsulation" by Scott Meyers
> >
> > http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/1844
> > 01197
> >
> > Note that I'm as guilty as anyone for not understanding or
> > following these guidelines. I expect we can do much better.
>
> As a counterpoint. I guess UFCS makes it less of a problem, but
> it's nice when using an IDE to just type foo. , press ctrl-space
> and see a nice list of methods that can be used with the class.
> When having free functions, you don't get to enjoy that :)

At a previous job, we had our own string class which wrapped std::string
just because some of the developers wanted our extra string functions on the
type where they would be easy to find (even just for documentation
purposes). They were of the opinion that once you separate the functions
from the class, your project will ultimately end up with multiple header
files of functions doing similar things, because at least some of the time,
developers wouldn't know about the existing functions and would add their
own own. And with sufficiently large projects, that does seem to happen all
too often. I still don't agree with the idea that putting stuff on the class
is better just because it makes stuff easier to find, but I can see why
someone would think that.

As has been pointed out elsewhere in this thread, the encapsulation benefits
don't exist in the same way in D unless you put the free functions in
separate modules, and then you have to import other stuff to use them,
whereas in C++, you can just put the free functions next to the type and
still get the encapsulation benefits. So, the benefit of splitting the
functions out within a module is fairly minimal in D. Rather, the main
reason I see for splitting functions out is in order to make them more
generic, and I think that the push to do that in D has a tendency to make a
lot of functions free functions that might have been member functions in
most other languages.

And in D, there's the issue that declaring a function to be used with UFCS
instead of as a member function can be a bit of a pain when the type is
templated. You have to repeat a bunch of stuff that's just part of the
templated struct or class. You end up with additional templates and template
constraints (much of which is duplicated) just to separate the functions
from the type.

That being said, the time that I'm most likely to turn a member function
into a free function when the function isn't going to be made generic is
when the type is templated simply because then I can put the unittest block
right next to the function without having it be part of the template (since
that's almost always the wrong thing to do if you don't do some boilerplate
with static ifs to make it so that they're only compiled into a single
instantiation that's intended just for testing).

Overall, I think that the idea that functions should be free functions where
reasonable is good advice, but it needs to be taken with a grain of salt.

- Jonathan M Davis



More information about the Digitalmars-d mailing list