Assert!(a == b) or assert_eq!(a, b)


#1

I was looking at iter documentation, and noticed a mixture of the two assert macros:

assert!(a == b);
// vs.
assert_eq!(a, b);

Which is preferred?


#2

The respective part of the rust book uses assert_eq! where appropriate, so probably that.


#3

assert_eq provides better diagnostics, otherwise I would favour ==.


#4

With the change in semantics of fmt::Show, you can now likely use assert_eq for more things. It used to be that it didn’t make sense to implement Show on some types, like Path, and so they couldn’t work with assert_eq. That’s changed.


#5

It also generates more code to format the values. So I use assert_eq! in tests and prefer assert! (with a case-specific panic message, if appropriate) in production code.


#6

Oh definitely, assert_eq! is a testing tool. Stick to assert or debug_assert in actual code.


#7

If I understand correctly, this is neither in testing code nor in actual code but from an example in the documentation, a case of its own.

I prefer to use assert!(a == b) in examples, when “demoing” equality while making sure the example is testable. (Remember it is an example in the documentation as first priority, and testable code to make sure the example works is second priority.)

I prefer assert!(a == b) thinking that the reader of the documentation will find it more obvious. It may in fact be me that wrote part of the iterator docs and contributed to the inconsistency(!) :smile:


#8

If I remember correctly, there were talks at one point about modifying assert! to give more diagnostics about common operators like == and !=. I’m assuming that a change like that would be firmly post-1.0, but has there been any more talk about it?


#9

Unfortunately changes to the macro design (how expressions are chunked out) has rendered this impossible.


#10

Yes, the issue got closed for that reason.


#11

I get that it would be impossible to do as a macro_rules!() (as the == is part of the expression), but couldn’t a syntax plugin look at the AST node for the expression it read in, and check if it is an == operator, generating different code if it is? I’m not super familiar with syntax plugins, so I’m not sure if this is possible. I suppose it would also make the use of assert_eq!() impossible without unstable language features… So that’s a downside.


#12

I’ve made some measurements comparing performance of assert! and assert_eq! on part of the Rust’s own test suite (namely, tests in src/test).

First, I replaced all the assert!s with assert_eq!s where possible on branch assert1, then replaced all assert_eq!s with assert!s on branch assert2 (the difference is approximately 2350 assertions), then I measured the time spent on compiling and running the tests. Here’s the results:

assert1:
real    7m27.344s
user    0m0.885s
sys     0m2.306s
assert2:
real    7m19.202s
user    0m1.299s
sys     0m4.011s
assert1:
real    7m22.374s
user    0m1.143s
sys     0m4.053s
assert2:
real    7m20.605s
user    0m1.285s
sys     0m4.339s
assert1:
real    7m23.646s
user    0m1.219s
sys     0m4.116s
assert2:
real    7m19.442s
user    0m1.390s
sys     0m3.978s

On average, the slowdown from assert_eq! is about 1%, which is quite acceptable given that assert_eq! is much more useful when something actually breaks.
I’ll open a pull request replacing assert! with assert_eq! in tests.


#13

It’s not impossible, it’s just maybe not advisable! I managed to sort out how to split a stream of tokens on arbitrary token and re-parse both sides as expressions… (coming soon to itertools: iterator comprehension macro again)

Link to back this craziness up


#14

Would that enable Spock-like reporting?


#15

Well it could report values on both sides of == but going further would probably require too crazy macros?


#16

How crazy? I mean, reporting like that can be incredibly useful, though in the real world, the usefulness is often reduced by large textual representations that make it hard to see what is what.

Another problem of this approach is that in groovy or Java, every object has a (possibly useless, but existing) .toString() method, which is a boon for reporting like this. In Rust, we cannot know if a type implements Show or even Debug, and if I’m not mistaken it’s impossible to create a coherent trait that dispatches to Debug if available and to Show otherwise, right?


#17

Yes we have no specialization / fallback like that right now. So for example, current assert_eq! will only work with types that impl Debug.


#18

That story should change once RFC #1148 is implemented (hopefully).

Then we could implement a helper trait for Debug, for Show + !Debug and for !Show + !Debug with different code paths (Show Debug representation where available, else show normal representation, finally just fall back on showing the source).