Is there a reason NSDecimalNumber is not Comparable?

Cc @Philippe_Hausler @scanon

NSDecimalNumber’s bridged variant, Decimal, does conform to Comparable. Is there a reason you need to keep these numbers in their reference form?

NSDecimalNumber is not a standalone class -- it is part of a class hierarchy. It subclasses NSNumber, and that superclass would arguably be a better point to introduce a Comparable conformance.

Operators such as < and == aren’t overridable in Swift, so class hierarchies that conform to Comparable typically need to provide overridable hooks to let subclasses customize the implementation. Luckily, NSNumber already provides the overridable method NSNumber.compare(_:) to implement a heterogeneous three-way comparison, and it customizes NSObject.isEqual(_:) to call it. So it would be technically possible to add the Comparable conformance without changing Foundation's Objective-C API.

However, it wouldn’t necessarily be a good idea. For bridged types, we generally prefer to keep the battle-proven Cocoa APIs as pristine as possible, and we spend most effort on improving the API integration of the corresponding Swift type instead. For example, while Array is a fancy-pants mutable random-access range-replaceable ordered collection, but NSMutableArray is merely a sequence.

The assumption is that people would prefer to use Swift-native bridged types in most cases. This is encouraged by how Swift automatically bridges parameter types while importing Objective-C APIs. However, when Swift code needs to work with the original Cocoa types, it is generally more useful to work with the original Cocoa API, with little to no Swift-only additions. (Except for the usual, mostly mechanical naming & type signature transformations.) For example, NSMutableArray’s API would be rather confusing if it supported RangeReplaceableCollection requirements in addition to its own methods.

This is not a theoretical concern; we’ve seen how subtle details of NSObject’s Equatable/Hashable conformance has caused a great deal of confusion over how to customize equality/hashing in its subclasses. People don’t subclass NSNumber very often, but why add another pitfall? compare(_:) is already tricky enough to implement on its own — and adding a ‘<‘ overload would likely lead to the same problems as NSObject’s definition for ==.

2 Likes