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