ranges of characters and the overabundance of traits that go with them

H. S. Teoh via Digitalmars-d digitalmars-d at puremagic.com
Thu Mar 16 09:29:04 PDT 2017


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


More information about the Digitalmars-d mailing list