std.unittests for (final?) review

Michel Fortin michel.fortin at michelf.com
Wed Jan 5 21:09:07 PST 2011


On 2011-01-05 22:57:00 -0500, Jonathan M Davis <jmdavisProg at gmx.com> said:

> On Wednesday 05 January 2011 19:35:13 Michel Fortin wrote:
>> I'm not sold on the concept. The whole point of this module seems to
>> offer a way to replace the built-in assertion mechanism with a
>> customized one, with the sole purpose of giving better error messages.
>> So we're basically encouraging the use of:
>> 
>> 	assertPredicate!"a > b"(a, b, "message");
>> 
>> instead of:
>> 
>> 	assert(a > b, "message");
>> 
>> It looks like an uglification of the language to me.
>> 
>> I agree that getting better error messages is important (very important
>> in fact), but keeping the code clean is important too. If the built-in
>> assert doesn't give us good enough error messages, perhaps it's the
>> built-in assert that should be improved. The compiler could give the
>> values on both side of the operator to the assertion handler, which
>> would in turn print values and operator as part of the error message.
>> 
>> So to me this module is a temporary fix until the compiler is capable
>> of giving the necessary information to the assertion handler. I sure
>> hope it won't be needed for too long.
>> 
>> (Note: this criticism doesn't apply to those assertions dealing with
>> exceptions.)
> 
> Well, I'm not about to claim that assert can't be fixed to give better error
> messages, but right now all it takes is a value which converts to bool for the
> test. a > b may obviously be convertible to something similar to
> assertPred!">"(a, b), but what about something like 1 + 1 < b or a < b < c. As
> expressions get progressively more complicated, it very quickly becomes non-
> obvious what someone would really want to print on error. Would 1 + 1 < b print
> 2 and b's value? Would it print 1, 1, and b's value? 1, 1, 2, and b's value?
> Sure, it may be obvious to the programmer what they intended, but it doesn't
> take much for it to be very difficult for the compiler to figure it out 
> for you.

I think "assert(1+a < b)" should print the same thing as "static 
assert(1+a < b)" does. What "static assert(1+a < b)" prints when a == 1 
and b == 0 is "(2 < 0) is false". Try it yourself.


> Also, assertPred!">"(a, b) would print out a more informative error message on
> its own. You wouldn't need to give it an additional message for it to be more
> informative. That would defeat the point. Even assertPred!"a > b"(a, b) 
> could be
> more informative (assuming that it treats a > b as a general predicate rather
> than determining that it's actually >) by printing the values that it's given.
> So, that's definitely a leg up on assert(a > b) right there.

I don't believe it to be that difficult. From inside the compiler, you 
have access to the expression tree. All the compiler needs to do is 
check whether the top level expression is a binary op, and if so 
decompose it this way (assuming no given message here):

	auto a = operand1;
	auto b = operand2;
	if (a <binaryop> b)
		_d_assert_msg2("(%s <binaryop> %s) is false", __FILE__, __LINE__, &a, 
typeid(a), &b, typeid(b));

As for other expressions it could simply print the value by lowering it 
this way:

	auto result = <expression>;
	if (result)
		_d_assert_msg1("(%s) is false", __FILE__, __LINE__, &result, typeid(result));

That would basically give you the same error messages as static assert.

Currently, assertions are lowered like this instead:

	if (expression)
		_d_assertm(moduleinfo, __LINE__);

or like this when a message is provided:

	if (expression)
		_d_assertm(<message>, __FILE__, __LINE__);

Sure, it's more complicated than doing it for static asserts where 
everything is known at compile-time, but I don't believe it to be that 
difficult.


> By passing each of the values to assertPred, we're able to print them out on
> failure without the computer having to understand what the predicate does, even
> when the values are arbitrary expressions. That would be very hard to 
> do with an
> improved assert which just took the expression. I mean, try and write a 
> function
> that took 1 + 1 > b or a < b < c as a string and tried to correctly print out
> values which are meaningful to the programmer. That would be _really_ hard. And
> while assertPred may not be able to understand a generic predicate, it can know
> about specific operators and/or functions and therefore give more informative
> error messages than it would be able to do with a generic predicate.

It's hard to do using a function. But it's easy for 'assert' because 
it's a language construct handled by the compiler.


> So, correctly implemented, I think that assertPred actually makes a lot more
> sense than trying to soup up assert and getting the compiler to guess at what
> the programmer really wants.

I don't really see what the compiler has to guess. The compiler just 
takes the top-level expression and pass its value to the assertion 
handler, and for binary expressions it can pass two values plus the 
operator's string. What cases are not covered by that?


-- 
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/



More information about the Digitalmars-d mailing list