Do non-member functions improve encapsulation in D?

Lars T. Kyllingstad via Digitalmars-d digitalmars-d at puremagic.com
Mon Apr 21 06:46:18 PDT 2014


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!


More information about the Digitalmars-d mailing list