4 ms·
For me, the exciting parts are in > Libs: Don't generate PartialEq::ne in derive(PartialEq) Meaning: Smaller generated code leading to faster compile times >
by epage 4y ago
For me, the exciting parts are in
> Libs: Don't generate PartialEq::ne in derive(PartialEq)
Meaning: Smaller generated code leading to faster compile times
> Cargo: Take priority into account within the pending queue.
When not enough CPUs are available (particularly CI), cargo will now prioritize crates with the longest dependency chain. We are wanting to be even smarter about which crates get priority but we still need to figure out what are acceptable heuristics (as we don't want to hard code crate names)
- kibwen 4y agoThanks to you and the Cargo team for all your efforts!
- epage 4y agoThanks though lqd is the one to thank the most for the performance work. I really appreciate the build time performance folks (nick, lqd) are looking at things holistically rather than staying in one specific domain.
- brundolf 4y ago> Don't generate PartialEq::ne in derive(PartialEq) I had to look at the docs to understand what was going on here so I thought I'd share: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html https://doc.rust-lang.org/std/cmp/trait.PartialEq.html Apparently the PartialEq trait has two methods - eq and ne (equal and not-equal, == and != respectively). Normally you only implement eq, because ne has a default implementation that's just !self.eq(other). The docs even say: > Implementations must ensure that eq and ne are consistent with each other > The default implementation of ne provides this consistency and is almost always sufficient. It should not be overridden without very good reason. So I'm guessing that `derive(PartialEq)` used to actually generate a fresh ne in each usage (even though presumably it was equivalent to !self.eq(other)), instead of just falling back to the default implementation. I can definitely see that having an impact on compile times. Do I have that right? Addendum: Now I'm trying to think of a case where you'd want a custom implementation of ne... I'm not sure I can come up with one
- insanitybit 4y agoMy understanding is that you are right. As for when it would be useful to override `ne`, very hard to say. The only case I can think of would be to add temporary debug info.
- unrealhoang 4y agoMaybe a data structure where you have an array of data and its hashed value, an eq implementation needs to go over the array to compare, but the ne implementation can short circuit by just comparing the hash. hash(a) != hash(b) => a != b, the reverse doesn't hold.
- brundolf 4y agoI thought about that sort of thing too, but eq returns equal-or-not-equal, so it could apply the same short-circuit Simpler example: if two lists don't have the same length you know they're unequal without looking at the items. But you could early-terminate eq the same way and actually benefit both eq and ne
- remram 4y agoThat is not true, the eq method can also short-circuit, in the same situation (hashes are different).
- zbentley 4y ago> I'm trying to think of a case where you'd want a custom implementation of ne... I'm not sure I can come up with one One old example from school was comparing unordered sets of numbers, each backed by a flat array. Summing such an array, contiguous in memory, was very fast: faster than many individual numeric comparisons. So "not equals" checked for equal sums before dropping back to iteration. Of course, that only made sense in situations where more things weren't equal (and didn't share sums) than not, but it helped someone win some performance/vanity extra credit. And I didn't know about vectorized code at the time, so that might make it a wash. A similar example might be with probablistic checksums of large data. If a checksum answers "maybe the same or definitely not the same" a la a HyperLogLog, comparing checksums is a quick way out for "not equals". Of course, that'd require some uniquely small/untrustworthy checksums, or some uniquely paranoid comparison programmers! That applies similarly to "equals", though. About the only even vaguely realistic example I can think of is for non-complementary notions of equality and inequality, i.e. an application context in which case it makes sense to have rules like "two MyLists are equal if they contain the same elements, but are not equal if they contain different elements or have different orders". And I call that "realistic" because I've seen code do things like that .... not because it's anything but a terrible idea.