std.unittests for (final?) review

Nick Sabalausky a at a.a
Thu Jan 6 02:03:51 PST 2011


"Jonathan M Davis" <jmdavisProg at gmx.com> wrote in message 
news:mailman.450.1294300236.4748.digitalmars-d at puremagic.com...
> On Wednesday 05 January 2011 23:08:21 Nick Sabalausky wrote:
>> "Jonathan M Davis" <jmdavisProg at gmx.com> wrote in message
>> news:mailman.446.1294293885.4748.digitalmars-d at puremagic.com...
>>
>> > What about something like a < b && c < d? If assertPred!() takes more
>> > than two parameters (as I would hope it would), then you could do
>> > something like
>> > assertPred!((a, b, c, d){return a < b && c < d;})(foo(), bar(), 
>> > hello(),
>> > world()) and it could not only tell you that the predicate failed, but 
>> > it
>> > could
>> > tell you that the values that it was given were 1, 5, 4, and 2. How 
>> > could
>> > assert(foo() < bar() && hello() < world()) do that? It has to know 
>> > where
>> > to stop
>> > the expressions evaluation to print it.
>>
>> How about this set of rules?:
>>
>> As the compler evaluates the assert's expression tree starting from the
>> root:
>>
>> 1. Literals DO NOT have their values printed.
>> 2. Built-in-operator expressions (arithmetic, parens, comparison, etc) DO
>> NOT have their values printed, but the compiler traverses their immediate
>> sub-expressions.
>> 3. Variables DO have their values printed.
>> 4. Things that take parameters (such as a function call or an eponymous
>> template instantiation) DO have their values printed, but the compiler 
>> does
>> *not* traverse the parameters (unless this is the root-level expression).
>
> I think that that you'd have to give some examples for it to be clear what
> exactly you mean, but it sounds like this would print a lot more values 
> than
> would be desirable in complex expressions. With assertPred, I could do 
> something
> like
>
> assertPred!"=="(foo(bar(g, none("abc")) * 2, hello(world(i)) + 2 * 
> func(funky(2
> + q)), 25)
>
> and get what the actual result was. e.g. "== failed: 14 != 25". I wouldn't 
> want
> all of those arguments printed. It's the final result that matters. If I
> understand what you're suggesting, a lot of those arguments would be 
> printed in
> your suggestion, which would be less than desirable, I think. Granted, 
> that
> particular example is quite ugly, but I'd like to be able to test 
> arbitrarily
> complex functions and still get a reasonably informative error when the 
> test
> fails.
>

Your example is missing a closing paren, I assume you meant:

    assertPred!"=="(foo(bar(g, none("abc")) * 2, hello(world(i)) + 2 * 
func(funky(2 + q))), 25)

Ie, assertPred is given two run-time arguments, the first of which is a call 
to foo. And foo is given two arguments: "bar(...)*2" and 
"hello(...)+2*func(...)".

Under my suggestion, that example would be:

    assert(foo(bar(g, none("abc")) * 2, hello(world(i)) + 2 * func(funky(2 + 
q))) == 25)

If that fails, it would first print something like:
    file(line): Assert failed: foo(bar(g, none("abc")) * 2, hello(world(i)) 
+ 2 * func(funky(2 + q))) == 25

Then it would inspect the expression: The root-level expression is "stuff == 
25". The right-hand-side, 25, is a literal, so that's ignored (rule #1). The 
left-hand side is the expression "foo(param1, param2)", so it's value (14 in 
your example) gets displayed (rule #4):

   [foo(bar(g, none("abc")) * 2, hello(world(i)) + 2 * func(funky(2 + q)))]: 
14

Since foo is something that takes params (it's a function call) and it's not 
the root expression (the == is the root expression), foo's params are 
ignored (rule #4) and everything is now done.

Alternatively, the rules could be followed like this:

Start with the whole expression, but do not print anything yet. Look at the 
root expression: It's "stuff == 25". The 25 is a literal, so leave it as-is 
(essentially rule #1). The other side is a function call, so replace the 
expression "foo(...,...)" with it's value, 14 (essentially rule #4). Now 
there's no more subexpressions left to process, so display the 
newly-modified expression: 14 == 25

Under the other example you had:

    assert(foo() < bar() && hello() < world())

The expression tree looks like this:

- Root: &&
    - LHS of &&: <
        - LHS of <: foo()
        - RHS of <: bar()
    - RHS of &&: <
        - LHS of <: hello()
        - RHS of <: world()

The root is &&, so we dive into it's operands (rule #2). Both of those are 
<, so we dive into their respective operands (rule #2). Now we have four 
things that take params (I'm conveniently ignoring the fact that the number 
of params they actually take just happens to be 0), so we either display or 
substitute-in their values and dive no further (rule #4), and get either:

Failed: foo() < bar() && hello() < world()
foo(): 4
bar(): 3
hello(): 2
world(): 1

Or just: 4 < 3 && 2 < 1

Note that due to the way rule #2 is written, if you replaced "foo()" with 
"f() + oo()", then you would get something like:

2 + 2 < 3 && 2 < 1

Which I don't think is too bad, particularly considering the expression it 
came from. And is is more information, which could be helpful - you can 
always add them together, but if it just gives you "4" you can't un-add it.

But I also like your idea of "if the evaluation was stopped when all that 
was left in the expression was boolean operators and their operands". I 
can't tell right now since it's late and I'm half asleep, but I think my 
suggestion is essentially very similar. In fact, it might be exactly the 
same if you changed my rule #2 to just be comparison and boolean-logic 
operators and treat the other operators as functions (ie, move arithmetic 
and bitwise-logic operators from rule #2 to rule #4).

In any case, the details of the rules can be tweaked, but the main point is 
I think it's doable. That said, I still see the value in assertPred both for 
the meantime and to avoid the catch-22 someone mentioned of (paraphrasing) 
"Do we define this in the language thereby complicating the language and 
preventing alternate compilers from improving on it, or do we leave it out 
of the langauge definition and not guarantee these benefits to users of 
alternate compilers?"




More information about the Digitalmars-d mailing list