Rant after trying Rust a bit

H. S. Teoh via Digitalmars-d digitalmars-d at puremagic.com
Fri Jul 24 11:50:02 PDT 2015


On Fri, Jul 24, 2015 at 11:29:28AM -0700, Walter Bright via Digitalmars-d wrote:
[...]
> Overloading with constraints is commonplace in Phobos. Haven't really
> had any trouble with it.
[...]

Actually, I've had trouble with overloading with constraints. Unlike
C++, D does not allow multiple possible template instantiations in
overload sets. While this is ostensibly a good thing, it makes writing
fallbacks extremely cumbersome.

For example, suppose I have a set of overloads of myFunc(), each of
which specifies some set of constraints defining which subset of types
they are implemented for:

	void myFunc(T)(T t) if (someSetOfConditions!T) { ... }
	void myFunc(T)(T t) if (someOtherSetOfConditions!T) { ... }
	void myFunc(T)(T t) if (yetAnotherSetOfConditions!T) { ... }

As long as the conditions are mutually exclusive, everything is OK.

But suppose these conditions describe specializations of the function
for specific concrete types (e.g. I want to take advantage of extra
properties of the concrete types to implement faster algorithms), but I
want a fallback function containing a generic implementation that works
for all types. Unfortunately, I can't just write another overload of
myFunc without constraints, because it causes conflicts with the
preceding overloads. The only way to achieve this is to explicitly
negate every condition in all other overloads:

	// generic fallback
	void myFunc(T)(T t)
		if (!someSetOfConditions!T &&
		    !someOtherSetOfConditions!T &&
		    !yetAnotherSetOfConditions!T) { ... }

This isn't too bad at first glance -- a little extra typing never hurt
nobody, right? Unfortunately, this doesn't work if, say, all these
overloads are part of some module M, but the user wishes to extend the
functionality of myFunc by providing his own specialization for his own
user-defined type, say, in a different module. That is prohibited
because the generic myFunc above doesn't have the negation of whatever
conditions the user placed in his specialization, so it will cause an
overload conflict.

It is also a maintenance issue that whenever somebody adds or removes a
new specialization of myFunc (even within module M), the sig constraints
of the generic fallback must be updated accordingly.

It gets worse if the original sig constraints were buggy -- then you
have to fix them in both the specialization and the generic fallback --
and hope you didn't miss any conditions (e.g. a typo causes the generic
fallback not to pick up something that the specialization now declines).

If you think this is a contrived scenario, you should take a look at
std.conv, where this particular problem has become a maintenance
headache. Among the several dozens of overloads of toImpl, there are all
kinds of sig constraints that, at first glance, isn't obvious whether or
not they cover all the necessary cases, and whether various fallbacks
(yes there are multiple! the above scenario is a simplified description)
correctly catch all the cases they ought to catch. When there is a bug
in one of the toImpl overloads, it's a nightmare to find out which one
it is -- because you have to parse and evaluate all the sig constraints
of every overload just to locate the offending function.

Maybe as a Phobos *user* you perceive that overloading with sig
constraints is nice and clean... But as someone who was foolhardy enough
once to attempt to sort out the tangled mess that is the sig constraints
of toImpl overloads, I'm getting a rather different perception of the
situation.


T

-- 
What do you mean the Internet isn't filled with subliminal messages? What about all those buttons marked "submit"??


More information about the Digitalmars-d mailing list