Rant after trying Rust a bit

H. S. Teoh via Digitalmars-d digitalmars-d at puremagic.com
Thu Jul 23 18:05:57 PDT 2015


On Thu, Jul 23, 2015 at 05:34:20PM -0700, Walter Bright via Digitalmars-d wrote:
> On 7/23/2015 3:06 PM, H. S. Teoh via Digitalmars-d wrote:
> >OK, I jumped into the middle of this discussion so probably I'm
> >speaking totally out of context... but anyway, with regards to
> >template code, I agree that it ought to be thoroughly tested by at
> >least instantiating the most typical use cases (as well as some
> >not-so-typical use cases).
> 
> I argue that every code line of the template must at least have been
> instantiated at some point by the test suite. Anything less is,
> frankly, unprofessional.

I agree, and I didn't claim otherwise.


> >A lot of Phobos bugs lurk in rarely-used template branches that are
> >not covered by the unittests.
> 
> Generally when I work on a Phobos template, I upgrade it to 100% unit
> test coverage. This should be a minimum bar for all Phobos work. We
> ought to be ashamed of anything less.

Agreed.


> >Instantiating all branches is only part of the solution, though. A
> >lot of Phobos bugs also arise from undetected dependencies of the
> >template code on the specifics of the concrete types used to test it
> >in the unittests.  The template passes the unittest but when you
> >instantiate it with a type not used in the unittests, it breaks. For
> >instance, a lot of range-based templates are tested with arrays in
> >the unittests. Some of these templates wrongly depend on array
> >behaviour (as opposed to being confined only to range API operations)
> >while their signature constraints indicate only the generic range
> >API. As a result, when non-array ranges are used, it breaks.
> >Sometimes bugs like this can lurk undetected for a long time before
> >somebody one day happens to instantiate it with a range type that
> >violates the hidden assumption in the template code.
> 
> I agree that the constraint system is not checked against the actual
> body of the template. Dicebot brought that up as well. Some attention
> should be paid in the unit tests to using types that are minimal
> implementations of the constraints.
> 
> That said, it is a pipe dream to believe that if something matches the
> function signatures, that it is correct and will work without ever
> having been tested.

I didn't say that this one thing alone will singlehandedly solve all of
our template testing woes. Obviously, it cannot catch semantic errors --
you use all the valid range API operations, but you use them in the
wrong order, say, or in a way that doesn't accomplish what the code is
supposed to do.  I think it's a given that you still need to adequately
unittest the code just like you would non-template code.

Nevertheless, this does help to eliminate an entire class of latent
template bugs -- hidden dependencies on the incoming type that are not
covered by the function's contract (i.e., signature constraints).
Relying on the programmer to always use types with minimal functionality
in the unittests is programming by convention, and you know very well
how effective that is. Without enforcement, we have no way of being sure
that our tests are actually adequate. An untested branch of template
code can be detected by using -cov, but performing an operation on an
incoming type without checking for it in the sig constraints cannot be
detected except by reading every line of code. The unittest may have
inadvertently used a type with a superset of functionality, but since
this is never enforced (and the current language provides no way to
actually enforce it) we can never be sure -- we're just taking it on
faith that the tests have covered all bases.

With actual language enforcement, we can actually provide some
guarantees. It doesn't solve *all* the problems, but it does solve a
significant subset of them.


> >If we had a Concepts-like construct in D, where template code is
> >statically constrained to only use, e.g., range API when manipulating
> >an incoming type, a lot of these bugs would've been caught.
> >
> >In fact, I'd argue that this should be done for *all* templates --
> >for example, a function like this ought to be statically rejected:
> >
> >	auto myFunc(T)(T t) { return t + 1; }
> >
> >because it assumes the validity of the + operation on T, but T is not
> >constrained in any way, so it can be *any* type, most of which,
> >arguably, do not support the + operation.
> 
> It's a valid point, but I'd counter that it'd be pretty tedious and
> burdensome. D isn't meant to be a bondage & discipline language. The
> failed exception specifications (Java and C++) comes to mind.
> 
> 
> >If the compiler outright rejected any operation on T that hasn't been
> >explicitly tested for, *then* we will have eliminated a whole class
> >of template bugs. Wrong code like the last example above would be
> >caught as soon as the compiler compiles the body of myFunc.
> 
> Yeah, but few would like programming in such a nagging, annoying
> language.

I have trouble thinking of a template function that's actually *correct*
when its sig constraints doesn't specify what operations are valid on
the incoming type. Can you give an example?

If such code is wrong, I'd say the language *should* reject it.

If you think that's too "bondange and discipline", what about a generic
wildcard sig constraint clause that says basically "type T works with
any operation you imagine"? Then those programmers who are too lazy to
figure out what operations are required for the function can just slap
this on, and continue writing broken code to their heart's content.


> Note that if you do instantiate with a type that doesn't support those
> operations, it isn't the end of the world - you'll still get a compile
> time error message.

Yes, but by then it's the user that is faced with an inscrutable
template error. If I'm a library author, I'd like to be able to find all
these bugs *before* shipping my code to the customers.


T

-- 
People tell me I'm stubborn, but I refuse to accept it!


More information about the Digitalmars-d mailing list