I 'm integrating a geographic coordinate class from CodePlex to my personal "toolbox" library. This class uses float
fields to store latitude and longitude.
Since the class GeoCoordinate
implements IEquatable<GeoCoordinate>
, I habitually wrote the Equals
method like so:
public bool Equals(GeoCoordinate other)
{
if (other == null) {
return false;
}
return this.latitude == other.latitude && this.longitude == other.longitude;
}
At this point I stopped and considered that I 'm comparing floating point variables for equality, which is generally a no-no. My thought process then went roughly as follows:
I can only imagine setting the
Latitude
andLongitude
properties once, which means that there will be no errors being accumulated to mess up my comparisons.On the other hand, it's possible (albeit pointless) to write
var geo1 = new GeoCoordinate(1.2, 1.2); var geo2 = new GeoCoordinate(1.2, 1.2); // geo1.Equals(geo2) will definitely be true, BUT: geo2.Latitude *= 10; geo2.Latitude /= 10; // I would think that now all bets are off
Of course this is not something I can imagine doing, but if the public interface of the class allows it then
Equals
should be able to handle it.Comparing for equality using a
difference < epsilon
test would solve the problem of comparing two instances, but create more problems:- How to make equality transitive? It sounds impossible.
How to produce the same hash code for all values that would compare equal?
Let's say that
epsilon = 0.11
(random example). It follows thatGeoCoordinate { 1, 1 }
would need the same hash code asGeoCoordinate { 1.1, 1.1 }
. But the latter would need the same hash code asGeoCoordinate { 1.2, 1.2 }
. You can see where this is going: all instances would need to have the same hash code.
A solution to all of this would be to make
GeoCoordinate
an immutable class. This would also solve theGetHashCode
problem: it is based on latitude and longitude (what else), and if these are are mutable then usingGeoCoordinate
as a key into a dictionary is asking for trouble. However, to make the class immutable has its own drawbacks:- You cannot instantiate-and-configure instances of the class (the WPF paradigm), which might be a pain in some cases
- Serialization would probably also become a pain due to the loss of a parameterless constructor (I 'm not a .NET serialization expert so that's as much detail as I see here)
Which approach would you suggest? It's easy to make the class fit the requirements I have right now (just make it immutable), but is there some better way?
Edit: I added an item 3 in the list above, shifting the previous item 3 to position 4.
Solution
I 'm going to allow some more time for feedback, but presently I 'm going with the immutable approach. The struct
(because that's what it is now) with the relevant members can be seen here; comments and suggestions more than welcome.