Q
Q
qRoC2017-07-24 20:26:07
Swift
qRoC, 2017-07-24 20:26:07

How to use optional types implementing Equatable in generics?

By default, Swift defines functions that implement Equatable to work with optional types.

var pA: UnsafeMutableRawPointer?
var pB: UnsafeMutableRawPointer?
print(pA == pB);

The problem is how to implement support for optional types for generics if you need to refine the implementation.
Simple example:
protocol AdapterProtocol {
    associatedtype IntegralType: Equatable

    init(_ value: IntegralType)
}

// Всё отлично, UnsafeMutableRawPointer реализует Equatable
struct Adapter: AdapterProtocol {
    var val: UnsafeMutableRawPointer

    public init(_ value: UnsafeMutableRawPointer) {
        val = value
    }
}

// Ошибка: does not conform to 'Equatable'
struct AdapterOptional: AdapterProtocol {
    var val: UnsafeMutableRawPointer?

    public init(_ value: UnsafeMutableRawPointer?) {
        val = value
    }
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Anton Zhilin, 2017-07-25
@qRoC

Obviously, it needs to be satisfied Optional<UnsafeMutableRawPointer> : Equatable. In theory, it should be enough to write:

extension Optional: Equatable where Wrapped: Equatable {
    func == (lhs: Optional<Wrapped>, rhs: Optional<Wrapped>) -> Bool
}

Only this doesn't work. This is a limitation of the current version of Swift 3.1.x and nothing can be done about it. The most interesting thing is that the == operator itself is already implemented in the standard library, but the extension is not. Alas.
The good news is that in Swift 4 this extension will work ( proposal ) and will be in the standard library.
Edit. The logical question is what to do right now. You are welcome:
struct EquatableWrapper<Wrapped: Equatable>: Equatable {
    var wrapped: Wrapped?
    init(_ newValue: Wrapped?) { wrapped = newValue }
}

func == <T: Equatable> (lhs: EquatableWrapper<T>, rhs: EquatableWrapper<T>) -> Bool {
    return lhs.wrapped == rhs.wrapped
}

struct AdapterOptional: AdapterProtocol {
    var val: UnsafeMutableRawPointer?
        
    public init(_ value: EquatableWrapper<UnsafeMutableRawPointer>) {
        self.val = value.wrapped
    }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question