Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Override PartialEq derives when a approx-partial-eq feature flag is enabled. #1085

Open
gibbz00 opened this issue Oct 9, 2023 · 4 comments

Comments

@gibbz00
Copy link
Contributor

gibbz00 commented Oct 9, 2023

Mostly a feature request that I'm interested in hearing your take on. It's quite common for me to have failed unit tests that check assert_eq! on structs with geometries, simply because of floating point rounding errors.

@gibbz00 gibbz00 changed the title Override PartialEq derives when approx feature flag is enabled. Override PartialEq derives when a approx-partial-eq feature flag is enabled. Oct 9, 2023
@michaelkirk
Copy link
Member

I don't think we should change PartialEq to be approximate, because I think this would surprise lots of people.

Instead, have you seen our usage of approx? There's probably some unit tests within our own repos that aren't yet using approx, but they should be if you feel like contributing.

@lnicola
Copy link
Member

lnicola commented Oct 11, 2023

@gibbz00
Copy link
Contributor Author

gibbz00 commented Oct 12, 2023

Maybe I'm being a bit misunderstood. Take this struct for example:

pub struct AddressSearch {
    id: Id,
    address_string: String,
    postal_info: Option<PostalInfoReference>,
    geometry: Point,
}

How would you go about unit testing equality of an expected value to an REST API call? Do I really want to check the equality of each and every field? What happens then when AddressSearch is included in another struct? It just doesn't scale.

A temporary solution that I'm currently using is manually implementing PartialEq where the floating point fields use approx:

impl PartialEq for AddressSearch {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
            && self.address_string == other.address_string
            && self.postal_info == other.postal_info
            && approx::relative_eq!(self.geometry, other.geometry, epsilon = 1e-6)
    }
}

Being able to override PartialEq with an opt-in feature flag makes this decision explicit, so it should not result in surprises by the user.

Overriding PartialEq in this crate was a "solution" that I thought was adequate, but probably not ideal. It might be worth attempting to solve this on a more general level with a separate derive macro. Maybe I should turn my efforts to approx?

@michaelkirk
Copy link
Member

Yeah, floating point makes comparisons annoying. It's not so much conceptually difficult, but it makes writing test code very verbose which is a pain.

But people assume a contract with PartialEq, and I think your suggested usage breaks that contract. For example, PartialOrd depends on the semantics of PartialEq. So I think implementing PartialEq like you're suggesting has ramifications on sorting, which could affect our other algorithms. If you want to do that in your own code, that's probably fine, but I don't think it's something we should expose, even as an optional feature.

If you want to be able to approximately compare your structs, I'd recommend implementing the approx::RelativeEq for your structs as well, like we have for the geometries in geo-types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants