On Thu, Mar 16, 2017 at 12:04:39PM +0000, Dukc via Digitalmars-d wrote: > On Monday, 13 March 2017 at 19:08:12 UTC, H. S. Teoh wrote: > > What the user sees should be the most generic API that makes sense > > relative to this function. For cases where the implementation can't > > (yet) handle, a helpful error message is given, and the docs should > > also indicate the present limitations. > > phobos each, and probably other functions too, is sometimes hard to > use because template constrains make them disappear when you enter > something faulty to them. Thus the error message only says something > like: No function overload "each" for arguments (...) found.
Exactly, this is why we need to seriously take up Walter's suggestion to simplify Phobos sig constraints. As I commented in a recent PR[1], Phobos functions need to accept *all* logically-acceptable arguments, and use static ifs internally to generate error messages when said arguments don't work with the current implementation for whatever reason. [1] https://github.com/dlang/phobos/pull/5148 - coincidentally, this one is about each(). In this PR about each(), there are 4 overloads, and the PR combines them into two. But they still have rather complicated constraints. However, if you look at it from a holistic POV, there really are only two constraints: (1) the argument can be iterated over with foreach; and (2) the argument has a range API. Thus, instead of having a whole bunch of complicated constraints that are hard to read and uninteresting to the user, the constraints really should be as simple as: void each(alias func, R)(R range) if (isInputRange!R) { ... } void each(alias func, R)(R range) if (!isInputRange!R && isForeachIterable!R) { ... } There, isn't that much more readable? Furthermore, whatever the current implementation can't handle, e.g. a range whose elements don't match the given function func, can be handled with static if's with an else clause that has an assert(0) with a nice error message. For example: void each(alias func, R)(R range) if (isInputRange!R) { static if (is(typeof(func(R.init.front)))) { foreach (e; range) func(e); } else static assert(0, "Range element type does not " "match function parameters"); } This way, if the user passes a range whose elements don't match the given function, they get a nice error message that explains what went wrong, instead of a generic "no matching function for call" with a wall of text in encrypted Klingon that nobody understands. T -- Latin's a dead language, as dead as can be; It killed off all the Romans, and now it's killing me! -- Schoolboy
