UFCS in generic libraries, silent hijacking, and compile errors.

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sat Mar 10 23:00:07 UTC 2018


On Saturday, March 10, 2018 21:50:42 aliak via Digitalmars-d-learn wrote:
> What are the recommended guidelines for using/not using UFCS in
> writing generic libraries?
>
> I ask because if you have an internal generic free function that
> you use on types in a generic algorithm via ufcs, then everything
> works fine until the type being operated on has a member function
> with a similar name.

The idea is that the type can provide its own version of the function that
is better optimized for it - e.g. it could potentially provide a member
function find that is more efficient for it than
std.algorithm.searching.find. That's actually the only technical reason why
UFCS is superior to the normal function call syntax. Everything else is a
matter of personal preference, though some folks prefer UFCS enough that
they use it everywhere. And as long as the code isn't generic, that's
usually not a problem, but using UFCS in generic code with a function that
isn't well-known can risk problems if it happens to match a member function.
The main reason that this isn't generally a problem is that most generic
code operates on either a fairly specific subset of types or on a specific
API where types implementing that API don't usually implement extra
functions (in particular, ranges normally only define the range API
functions, so it's rare that they have member functions that conflict with
anything). But if you're worried about it or want a specific function to be
called that definitely isn't a member function, then just don't use UFCS.
The situation that you're concerned about is not one that seems to be much
of an issue in practice. That doesn't mean that it's never a problem, but
from what I've seen, it's very rarely a problem, and it's easy to work
around if you run into a particular case where it is a problem.

The one case that I am aware of where best practice is to avoid UFCS is with
put for output ranges, but that has nothing to with your concerns here.
Rather, it has to do with the fact that std.range.primitives.put has a lot
of overloads for handling various arguments (particularly when handling
ranges of characters), and almost no one implements their output ranges with
all of those overloads. So, if you use put with UFCS, you tend to run into
problems if you do anything other than put a single element of the exact
type at a time, whereas the free function handles more cases (even if they
ultimately end up calling that member function with a single argument of the
exact type). We probably shouldn't have had the free function and the member
function share the same name.

> Is there something I'm not seeing as to why UFCS is not part of
> the overload set, and is there a way other than not using UFCS to
> prevent the silent hijacking?

If it were part of the overload set, then you have problems calling member
functions, particularly because there is no way to call a member function
other than with UFCS, whereas you can call free functions without UFCS, and
if you _really_ want to be sure that a very specific function is called,
then you can even give its entire module path when calling it. When UFCS was
introduced, it was decided that having member functions always win out would
cause the fewest problems.

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list