swiftcodableequatableencodable

Using JSONEncoder for Equatable method in Swift


I know JSON keys don't have any order and can be generated randomly, but there isn't anything preventing me from writing this function and from my tests this works on my every use case I tested.

func ==<T: Encodable> (lhs: T, rhs: T) -> Bool {
   let encoder = JSONEncoder()
   do {
       let leftEncoded = try encoder.encode(lhs)
       let rightEncoded = try encoder.encode(rhs)
       return leftEncoded == rightEncoded
   } catch {
       return false
   }
}

The problem I want to solve is writing a function for a type which has an array of one protocol with like 20 different implementation, which I have to implement the == function instead of swift auto synthesise. And I know I can switch to JSONSerialization.writeJSONObject with option .sortedKeys to persist the keys order.

What is the downside of this implementation instead of any other method of writing == function?


Solution

  • The answer seems to be in your question: "JSON keys don't have any order." Also, two things that are logically equal might encode differently (if their equality is dependent only on their id for example). Also, reference types that encode the same values may not be equatable at all (UIView for example). Also, this creates a very broad == overload that makes type-checking more expensive (much as + is extremely expensive).

    What you're doing is trying to auto-conform to Equatable when it can be synthesized. Swift could have done this; in fact, for most Encodable cases, Equatable can be synthesized just by adding : Equatable. The Swift team explicitly chose not to auto-conform in those cases and force you to request it when you mean it, because it doesn't always mean "all the properties contain the same bits." When the Swift team explicitly chooses to avoid a feature, it is rarely a good idea to re-add it.