class AnyComparable inherits from class AnyEquatable - swift

public class AnyEquatable: Equatable {
public let value: Any
private let equals: (Any) -> Bool
public init<E: Equatable>(_ value: E) {
self.value = value
self.equals = { $0 as? E == value }
}
public static func == (lhs: AnyEquatable, rhs: AnyEquatable) -> Bool {
lhs.equals(rhs.value) || rhs.equals(lhs.value)
}
}
public class AnyComparable: AnyEquatable, Comparable {
private let compares: (Any) -> Bool
public init<C: Comparable>(_ value: C) {
super.init(value)
self.compares = { ($0 as? C).map { $0 < value } ?? false }
}
public static func < (lhs: AnyComparable, rhs: AnyComparable) -> Bool {
lhs.compares(rhs.value) || rhs.compares(lhs.value)
}
}
I've got an error:
Overridden method 'init' has generic signature C where C:
Comparable which is incompatible with base method's generic signature
E where E: Equatable; expected generic signature to be C where C:
Equatable
Why does the compiler think that I'm overriding initializer? I didn't use the word "override". I can't override here because the method 'init' has different signature (which the compiler tells itself). It's not an overriding. I want the subclass to use its own initilizer, and I (obviously) don't want inherit superclass initializer.
So, how can I achieve that? What can be more natural than something comparable inherits from something equatable! Why can't I do that?

Note that your initialiser in the subclass does override the initialiser in the superclass. If you fix the constraint on C as the compiler asks you to, the next thing the compiler will tell you, is that you are missing an override keyword.
This behaviour is quite consistent, so it seems like it is deliberately designed that the generic constraints are not taken into account when determining whether one method overrides another. Here's another example of this:
class A {
func f<T>(t: T) {}
}
class B: A {
func f<C: Equatable>(t: C) {} // error
}
Anyway, one way you can work around this is to just change the argument label:
public init<C: Comparable>(comparable value: C) {
self.compares = { ($0 as? C).map { $0 < value } ?? false }
super.init(value)
}
The downside of this is that the client code gets a bit less concise. You have to do AnyComparable(comparable: something) every time, which is quite long. One solution is to put both AnyEquatable and AnyComparable in the same file, make both initialisers fileprivate. You can then provide factory functions (in the same file) that create these classes. For example:
public extension Equatable {
func toAnyEquatable() -> AnyEquatable {
.init(equatable: self)
}
}
public extension Comparable {
func toAnyComparable() -> AnyComparable {
.init(comparable: self)
}
}
Also note that your implementation of < doesn't make much sense. It should be:
public static func < (lhs: AnyComparable, rhs: AnyComparable) -> Bool {
lhs.compares(rhs.value) || (rhs != lhs && !rhs.compares(lhs.value))
}
and compares should mean "less than",
self.compares = { ($0 as? C).map { value < $0 } ?? false }
to say "lhs < rhs or rhs > lhs".
But even still, there are cases where using this class with completely unrelated types still doesn't make much sense, just FYI:
let a = AnyComparable(comparable: "foo")
let b = AnyComparable(comparable: 1)
print(a < b) // true
print(a > b) // true
print(a <= b) // false
print(a >= b) // false
print(a == b) // false
So please do be careful!

Related

Syntactic help: constraining functions to generic class

I have a structure that I simplified like this:
protocol Protocol {
associatedtype T
var common: T { get }
}
class Superclass<T>: Protocol {
let common: T
init(common: T) { self.common = common }
}
class IntClass<T>: Superclass<T> {
let int = 5
}
class StringClass<T>: Superclass<T> {
let string = "String"
}
class Example<P: Protocol> {
let object: P
init(object: P) { self.object = object }
func common() -> P.T { object.common }
func int() -> Int where P == IntClass<Any> { object.int }
func string() -> String where P == StringClass<Any> { object.string }
}
I would like to create objects of the generic class Example where some of them contain an object of the also generic IntClass while others have a generic StringClass object. Now I’d like to add accessors on Example for IntClass and StringClass specific properties (so I don’t have to access them directly). They would need to be constrained to the respective class. These would be int() and string() in my example.
My example doesn’t work like intended though:
let intExample = Example(object: IntClass(common: Double(1)))
// 👍 (= expected)
intExample.common() // Double 1
// 👍 (= expected)
intExample.string() // Instance method 'string()' requires the types 'IntClass<Float>' and 'StringClass<Any>' be equivalent
// 👎 (= not expected)
intExample.int() // Instance method 'int()' requires the types 'IntClass<Float>' and 'IntClass<Any>' be equivalent
I also tried:
func int() -> Int where P == IntClass<P.T> { object.int }
With these compiler complaints:
- Generic class 'Example' requires that 'P' conform to 'Protocol'
- Same-type constraint 'P' == 'IntClass<P.T>' is recursive
- Value of type 'P' has no member 'int'
And I tried:
func string<T>() -> String where P == StringClass<T> { object.string }
which, when using like intExample.string() results in Generic parameter 'T' could not be inferred (next to Instance method 'string()' requires the types 'IntClass<Double>' and 'StringClass<T>' be equivalent).
I don’t want string() to appear on an Example<IntClass> object in code completion.
Is there a syntax to accomplish what I want (anything with typealias?) or would I have to navigate around that problem?
Since the properties you are trying to access here doesn't depend on the type parameter T of IntClass or StringClass, you can write two non generic protocols HasInt and HasString:
protocol HasInt {
var int: Int { get }
}
protocol HasString {
var string: String { get }
}
extension IntClass: HasInt { }
extension StringClass: HasString { }
Then you can constrain to the protocols, and access int and string through the protocol instead:
func int() -> Int where P: HasInt { object.int }
func string() -> String where P: HasString { object.string }

Comparing Two Protocol Instances for Equality in Swift

Here's the deal,
I'm writing an SDK, and I want to declare observers as protocols, instead of classes or structs (It's sort of an "Observer/Delegate" hybrid).
I want to be able to compare two arguments that are passed in as protocol references, as opposed to the concrete classes/structs they actually are, IRL.
I know that the "easy" way to get comparison is to constrain the protocols to Hashable or Equatable, but I want to avoid burdening the user (It's an SDK).
Here's a little playground with what I mean:
protocol A {
func AFunc() -> String
}
class APrime: A {
func AFunc() -> String { "I AM GROOT" }
}
let variableA = APrime()
let variableB = APrime()
func compareTypes(_ inA: A, _ inB: A) -> String {
// if inA == inB {
// return ""
// }
return "not "
}
print("A is \(compareTypes(variableA, variableB))B.")
print("A is \(compareTypes(variableA, variableA))A.")
The raunchy bit is the commented-out section in compareTypes(_: A, _: A). I need to figure out how to compare them without going into "Hacksylvania," which I could do by doing something like comparing addresses of the AFunc() in each instance.
The expected output is:
A is not B.
A is A.
Any ideas for a more "swifty" approach? I must be missing the forest for the trees.
Just to add some closure to this, here is how I solve this:
protocol A {
var uuid: Int { get } // This is the secret sauce. It will contain a unique UUID, associated with the instance.
func AFunc() -> String
}
class APrime: A {
let uuid: Int = Int.random(in: 0..<1000) // The UUID is initialized with the instance.
func AFunc() -> String { "I AM GROOT" }
}
let variableA = APrime()
let variableB = APrime()
let variableC = variableA
func compareTypes(_ inA: A, _ inB: A) -> String {
if inA.uuid == inB.uuid { // We compare UUIDs.
return ""
}
return "not "
}
print("C is \(compareTypes(variableC, variableB))B.")
print("C is \(compareTypes(variableC, variableA))A.")
The "uuid" variable is usually an actual UUID type, but I didn't want to import Foundation in the example, so I just did a simple rand. It gets the point across.
This outputs:
C is not B.
C is A.
And there is another way (that I also use, sometimes):
protocol B {
func BFunc() -> String
func amIThisOne(_ instanceToCompare: B) -> Bool // This is an identity comparator
}
class BPrime: B {
func BFunc() -> String { "I AM GROOT'S BROTHER" }
// We compare ourselves against the other instance, assuming it can be cast to our own type.
func amIThisOne(_ inInstanceToCompare: B) -> Bool {
guard let instanceToCompare = inInstanceToCompare as? Self else { return false }
return self === instanceToCompare
}
}
let variableD = BPrime()
let variableE = BPrime()
let variableF = variableD
print("D is \(variableE.amIThisOne(variableD) ? "" : "not ")E.")
print("D is \(variableD.amIThisOne(variableF) ? "" : "not ")F.")
Which outputs:
D is not E.
D is F.
This allows a more programmatic way of comparing the instances.
HOW NOT TO DO IT
And then, of course, if we have control of the instances, we can truly do the Equatable thing (This requires that the playground import Foundation):
protocol C: Equatable {
func CFunc() -> String
}
class CPrime: C {
// This is actually not what I want, as I want to compare protocols, not conforming classes.
static func == (lhs: CPrime, rhs: CPrime) -> Bool {
guard let lhs = lhs as? Self else { return false }
guard let rhs = rhs as? Self else { return false }
return lhs === rhs
}
func CFunc() -> String { "I AM GROOT'S UDDER BROTHER" }
}
let variableG = CPrime()
let variableH = CPrime()
let variableI = variableG
print("G is \(variableG == variableH ? "" : "not ")H.")
print("G is \(variableI == variableG ? "" : "not ")I.")
Which outputs:
G is not H.
G is I.

What is the Swift equivalent for Java's Comparator Interface

I have the following Java code below that I am trying to convert into Swift accordingly. Can somebody help me on this issue. Thanks
public class CarsSortById implements Comparator<Cars>{
#Override
public int compare(Cars car1, Cars car2) {
return (car1.getCarId() < car2.getCarId()) ? -1:
(car1.getCarId() > car2.getCarId() ) ? 1:0 ;
}
}
Swift equivalent of Comparable<T>
Is the Comparable protocol. It requires that your type define an < operator. Since it derives from the Equatable protocol, you need to define the == operator, as well:
class Car {
let id: Int
// other fields
}
extension Car: Equatable {
static func == (lhs: Car, rhs: Car) -> Bool {
return lhs.id == rhs.id
}
}
extension Car: Comparable {
static func < (lhs: Car, rhs: Car) -> Bool {
return lhs.id < rhs.id
}
}
Swift equivalent of Comparator<T>
In Java, Comparator is an interface that lets you define sorting functions in addition to the one a type defines for itself via the Comparable Interface. Interfaces like this are necessary because Java didn't support lambdas prior to 1.8. And after Java 1.8, interfaces form the basis of lambdas.
Swift doesn't have an equivalent interface (called a protocol, in Swift). There's no need, since Swift can let you just define closures without the #functionalinterface cruft of Java.
Usually, Java Comparators are only used once. In this case, just call sort with a custom sorting closure:
let carsSortedByID = cars.sorted { $0.id < $1.id }
If you need to resume the sorting closure, you could assign it to a variable. Naturally, it would make sense to store these as static variable in an extension on the type that they sort.:
extension Car {
static let idSorter: (Car, Car) -> Bool = { $0.id < $1.id }
}
let carsSortedByID = cars.sorted(by: Car.idSorter)
As already mentioned in other answers and in the comment, in swift there is nothing for that. It is just closure.
But here is how you define Comparable
class Car {
var id = -1
}
extension Car: Comparable {
static func == (lhs: Car, rhs: Car) -> Bool {
return lhs.id == rhs.id
}
static func < (lhs: Car, rhs: Car) -> Bool {
return lhs.id < rhs.id
}
}
If you're looking to specifically replicate the Java Comparator behavior where it returns a negative number for "less than", zero for "equal", or a positive number for "greater than", you could write a function that returns a ComparisonResult.
ComparisonResult is an enum with the cases .orderedAscending, .orderedSame, and .orderedDescending.
You could rewrite your function in Swift:
extension Car {
func compare(with other: Car) -> ComparisonResult {
return self.carId < other.carId
? .orderedDescending
: self.carId > other.carId ? .orderedAscending : .orderedSame
}
}

Add sort to array wrapping class

The following code is from this answer: https://stackoverflow.com/a/28191539/4096655
public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = dispatch_queue_create("SynchronizedArrayAccess", DISPATCH_QUEUE_SERIAL)
public func append(newElement: T) {
dispatch_async(self.accessQueue) {
self.array.append(newElement)
}
}
public subscript(index: Int) -> T {
set {
dispatch_async(self.accessQueue) {
self.array[index] = newValue
}
}
get {
var element: T!
dispatch_sync(self.accessQueue) {
element = self.array[index]
}
return element
}
}
}
var a = SynchronizedArray<Int>()
a.append(1)
a.append(2)
a.append(3)
// can be empty as this is non-thread safe access
println(a.array)
// thread-safe synchonized access
println(a[0])
println(a[1])
println(a[2])
I am doing something very much like but am having trouble setting up a sort to pass to the array of generics. Ideally I'd like a sortInPlace but am not sure how to do it.
If you want to sort the wrapped array, then one way is to constrain T to a type conforming to Comparable. If you add this restriction, then a sorting function is easy to implement, simply ask the array to sort itself:
public class SynchronizedArray<T: Comparable> {
...
public func sortInPlace() {
array.sortInPlace(<)
}
For custom classes, you need to add an extension conforming to Comparable, and overload the == and < operators (reference here)
extension MyClass: Comparable {
}
func ==(lhs: MyClass, rhs: MyClass) -> Bool {
}
func <(lhs: MyClass, rhs: MyClass) -> Bool {
}
var a = SynchronizedArray<MyClass>()

Swift - Implementing Equatable?

I have the following class that I want to have Equatable. Everything works fine excep it seems like the operator completely overrides the global == operator.
// User.swift
class User: Equatable {
let id: Int
init(_ id: Int) {
self.id = id
}
}
func == (lhs: User, rhs: User) -> Bool {
return (lhs.id == rhs.id)
}
It seems like in other places in the code when I try to use == it complains that "T is not convertible to User". But this is a completely different class and has nothing to do with user
// ArrayExtension.swift
extension Array {
public func contains(object: T) -> Bool {
for x in self {
// Compile error here "T is not convertible to User"
if (x == object) {
return true
}
}
return false
}
}
What's wrong with the code
The problem is that the T in the Array is not necessarily Equatable. You cannot use == in your extension because of that.
The reason you get that error is that the compiler is trying its best to find a function that can be used called ==. It happens to be finding your == function but it gives an error because it doesn't actually match the types.
Note: The compiler could obviously use some usability work with its error messaging