On Monday, 21 April 2014 at 12:45:12 UTC, Steven Schveighoffer wrote:
[...]

Reasons off the top of my head not to make them module functions:

1. You can import individual symbols from modules. i.e.:

import mymodule: MyType;

If a large portion of your API is module-level functions, this means you have to either import the whole module, or the individual methods you plan to use.

Based on this, combined with your points 6 and 3 further down -- the second number 3, that is :) -- we can make the following guideline:

Methods which are central to the class' usage, and which are therefore likely to be used often, should be member functions, while auxiliary functions and convenience functions should be non-members.

The same thing was stated earlier in this thread, in different words, and I guess it is the rule most of us use already. However, this is the first non-subjective rationale I've seen for it so far. Awesome!

2. You can get delegates to methods. You cannot get delegates to module functions, even if they are UFCS compatible.

This is an excellent point.  I would never have thought of that.

3. There is zero chance of a conflict with another type's similarly named method.

How?  If you have the following functions:

    void foo(A a);
    void foo(B b);

and you write

    foo(new B);

there is also zero chance of conflict -- even if B happens to be a subclass of A, since the most specialised function is always called.

4. It enforces the "method call" syntax. I.e. you cannot use foo(obj) call. This may be important for readability.

Some would argue that giving users the choice between typing foo(obj) and obj.foo() is a Good Thing, because it doesn't impose your preferences on them. I'm not going to do that, though. ;)

5. You can only use operator overloads via methods. D is different in this respect from C++.

True. Operator overloads fall in the same category as virtuals and interface functions, i.e., the ones that *cannot* be non-members.

[...]

Reasons to make them module functions:

1. You have more than one object in the same file which implements the method identically via duck typing.

2. You want to change how the 'this' type is passed -- in other words, you want to pass a struct by value or by pointer instead of by ref.

3. The complement to #1 in the 'against' list -- you want your module-level API to be selectively enabled!

4. Of course, if you are actually implementing in a different module, Scott Meyers' reasoning applies there.

All very good points. This is exactly what I was looking for, thanks!

Reply via email to