On Tuesday, 4 February 2014 at 02:04:55 UTC, Chris Williams wrote:
And of course, even being able to read it, one would still need
to track down isInputRange() and isImplicitlyConvertible() to
know what they do.
Having to know what a particular concept does is pretty much the
same as having to know what an interface does. Even so,
`isImplicitlyConvertible` should be intuitive to programmers with
some experience in any statically typed language.
2. When using classes and interfaces, type checking is as
simple as writing the type to be passed in as a parameter. With
struct-typing, people need to manually append a series of
checks all over the place, which results in things like the
following:
auto uniform(T, UniformRandomNumberGenerator)(ref
UniformRandomNumberGenerator urng) if (!is(T == enum) &&
(isIntegral!T || isSomeChar!T));
Even though isUniformRNG() exists and is used on other
implementations of uniform(), it isn't used here, because
whoever developed the function forgot to include it on this
particular function.
Repeatedly needing to check for something nameless yet specific
like what the above does, is probably cause for introducing a new
concept.
I'll admit that getting constraints right is difficult, because
it's impossible to unit test whether an error happened because of
an immediate resolution failure or something else. We need some
improvement here if we want to keep aiming for tight constraints.
3. Non-extensible. To "extend" an SList or whatever, I would
have to write a wrapper class with methods that forward to the
SList methods, if I wanted my object to be able to interoperate
with Phobos, or I would need to modify Phobos so that the body
of SList was a template that could be mixed in (assuming I
didn't want to override any methods, just add new ones).
Use UFCS to add new methods.