On Sunday, 20 April 2014 at 07:11:41 UTC, Lars T. Kyllingstad
wrote:
In his article "How non-member functions improve encapsulation"
[1], Scott Meyers makes a good argument for why free functions
should generally be preferred over class methods in C++.
TL;DR: Fewer member functions means fewer functions that break
when the class implementation changes, and free functions can
be spread across different header files, allowing client code
to only #include the ones that are needed.
In D, the situation is somewhat different. Firstly, private
symbols are accessible throughout the module within which the
class/struct is defined, and secondly, UFC allows us to call
free functions using the same syntax as member functions. In
other words, *any* non-virtual function could in principle be
written as a free function.
The fact that "private" really means "module private" in D
means that any number of functions can break when a
class/struct implementation changes. So if we are to take
Meyers' advice, we have to define a new module for each
class/struct, and move its associated free functions to
neighbouring modules. However, this would lead to a
proliferation of modules that I doubt anyone would want.
So, can anyone think of some good guidelines for when to make a
function a member, when to write it as a free function in the
same module, and when to move it to a different module?
[1]
http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197
My rules that I try to adhere to are:
* Modules do one thing. All members of a module meet said modules
purpose.
I.e. std.traits is a great example of this, but std.algorithm not
quite so..
* Modules can have many free functions (I classify them as
checks) but few classes/structs unless its a defs file in which
case it can have quite a lot of them but few 'public' functions
and a lot of 'checks' functions.
* If it returns a new instance of a type and needs access to
private class/struct property then member.
* If it returns a new instance but doesn't need a types private
property then free.
* If it doesn't return a new instance of a type but may return
another type then member.
Generally speaking as long as you keep to the first (modules
purpose) rule then they stay smallish. Which is to me the most
important part.
Definition of a checks function is that they do one thing. They
get a single piece of information.