Equality + implicit = nasty_surprises


There is a maxim in API design: the principle of least surprise. Whatever an API does it must look obvious and self explanatory so that the developer that uses the API is not surprised by the result or any side effect of such API.

Implicit conversion operators in .NET make it so easy to surprise they should not even be considered in a good designed API.

Blaming by example

I wrote about a new member of the NMoneys family, a reference type that supplants Money when structs are not welcome: MonetaryQuantity.

What I wanted to achieve was a two-way conversion between MonetaryQuantity and Nullable<Money>. That conversion is perfectly safe as both types have the same null semantics.

If implicit operators from and to Nullable<Money> are implemented, one can write code that is succint:

If MonetaryQuantity implemented IEquatableComparer<MonetaryQuantity>, one could write code such as:

First two assertions pass because of the conversion of anotherFiver to Money? before hand. For the second assertion there is no conversion going on as Money?, since Nullable<> does not implement IEquatable<>, and there the .Equals(object) method is called.

Surely equality is commutative (or symmetric)! if a = b, then b = a. Right? Right? Not really, because in the first case, fiver is implicitly converted into MonetaryQuantity beforehand, but in the second assertion, again, no one “forces” anotherFiver to convert, and therefore reference equality kicks in.

The solution

Don’t implement implicit conversions. They look cute but will bring nasty bugs when used beyond cuteness. Just don’t. Design your APIs for minimum surprise. Please.

share class ,