Using ... as a concrete type conforming to protocol ... is not supported


(Jason Sadler) #1

I think Simon was referring to two separate problems in his post - first:

Using ‘KeyType' as a concrete type conforming to protocol 'Hashable' is not supported

And second:

type 'Key' constrained to non-protocol type ‘String’

The first error (which is of particular interest to me) you can reproduce with only the first half, leaving out MyProtocol entirely:

public protocol KeyType : Hashable {
    
}

public protocol ValueType {
    
}

struct MyConcrete {
    let values : [KeyType: ValueType]
}

I’m fairly new to Swift, and this is my very first time on the mailing lists, so forgive me if this has been answered before…but this seems to me like an arbitrary shortcoming of the compiler and not an intentional language design decision. (As I understand, this comes out of the fact that protocols don’t conform to themselves…?)

I wonder if anyone knows whether there are any plans to look at this corner of the language and allow this use case.

(My particular use case can be seen here: https://gist.github.com/sadlerjw/2cc16b4375b02fe7f400 … and the best information I’ve been able to find on this so far is here: http://stackoverflow.com/questions/33112559/protocol-doesnt-conform-to-itself/33524927#33524927)

Thanks
Jason


(Hooman Mehr) #2

Here is the best you can do for your particular use case:

protocol AnyEquatable { func equals(other: Any) -> Bool }

func ==<T: Equatable>(lhs: T, rhs: Any) -> Bool {
    
    if let rhs = rhs as? T { return lhs == rhs } else { return false }
}

extension Bool: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension Int: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension Double: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension String: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension Array {
    
    func indexOfAny(element : AnyEquatable) -> Index? { return indexOf { element.equals($0) } }
}

var array: [Any] = [false, 1, 2.0, "three"]

array.indexOfAny(2.0)

···

On Mar 25, 2016, at 2:51 PM, Jason Sadler via swift-users <swift-users@swift.org> wrote:

(My particular use case can be seen here: https://gist.github.com/sadlerjw/2cc16b4375b02fe7f400 … and the best information I’ve been able to find on this so far is here: http://stackoverflow.com/questions/33112559/protocol-doesnt-conform-to-itself/33524927#33524927)


(Hooman Mehr) #3

You can also get a heterogenous dictionary, but it needs a type erasing helper box. With the following declarations:

public func ==<T: Equatable>(lhs: T, rhs: Any) -> Bool {
    
    if let rhs = rhs as? T { return lhs == rhs } else { return false }
}

public struct AnyKey : Hashable {
    
    public let hashValue: Int
    public let key: Any
    public let equals: (AnyKey) -> Bool
    
    init<T: Hashable>(_ key: T) {
        
        self.hashValue = key.hashValue
        self.key = key
        self.equals = { self.key as! T == $0.key }
    }
}

public func == (lhs: AnyKey, rhs: AnyKey) -> Bool { lhs.equals(rhs) }

You can now create a heterogenous [AnyKey: Any] dictionary. Note that `AnyKey` is not very memory efficient.

···

On Mar 25, 2016, at 5:27 PM, Hooman Mehr <hooman@mac.com> wrote:

On Mar 25, 2016, at 2:51 PM, Jason Sadler via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

(My particular use case can be seen here: https://gist.github.com/sadlerjw/2cc16b4375b02fe7f400 … and the best information I’ve been able to find on this so far is here: http://stackoverflow.com/questions/33112559/protocol-doesnt-conform-to-itself/33524927#33524927)

Here is the best you can do for your particular use case:

protocol AnyEquatable { func equals(other: Any) -> Bool }

func ==<T: Equatable>(lhs: T, rhs: Any) -> Bool {
    
    if let rhs = rhs as? T { return lhs == rhs } else { return false }
}

extension Bool: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension Int: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension Double: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension String: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension Array {
    
    func indexOfAny(element : AnyEquatable) -> Index? { return indexOf { element.equals($0) } }
}

var array: [Any] = [false, 1, 2.0, "three"]

array.indexOfAny(2.0)


(Hooman Mehr) #4

Oops! that is buggy. I should check syntax before posting…

Here is the corrected version:

public struct AnyKey : Hashable {
    
    public let hashValue: Int
    public let key: Any
    public let equals: (Any, AnyKey) -> Bool
    
    init<T: Hashable>(_ key: T) {
        
        self.hashValue = key.hashValue
        self.key = key
        self.equals = { $0 as! T == $1.key }
    }
}

public func == (lhs: AnyKey, rhs: AnyKey) -> Bool { return lhs.equals(lhs,rhs) }

···

On Mar 25, 2016, at 5:59 PM, Hooman Mehr via swift-users <swift-users@swift.org> wrote:

You can also get a heterogenous dictionary, but it needs a type erasing helper box. With the following declarations:

public func ==<T: Equatable>(lhs: T, rhs: Any) -> Bool {
    
    if let rhs = rhs as? T { return lhs == rhs } else { return false }
}

public struct AnyKey : Hashable {
    
    public let hashValue: Int
    public let key: Any
    public let equals: (AnyKey) -> Bool
    
    init<T: Hashable>(_ key: T) {
        
        self.hashValue = key.hashValue
        self.key = key
        self.equals = { self.key as! T == $0.key }
    }
}

public func == (lhs: AnyKey, rhs: AnyKey) -> Bool { lhs.equals(rhs) }

You can now create a heterogenous [AnyKey: Any] dictionary. Note that `AnyKey` is not very memory efficient.

On Mar 25, 2016, at 5:27 PM, Hooman Mehr <hooman@mac.com <mailto:hooman@mac.com>> wrote:

On Mar 25, 2016, at 2:51 PM, Jason Sadler via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

(My particular use case can be seen here: https://gist.github.com/sadlerjw/2cc16b4375b02fe7f400 … and the best information I’ve been able to find on this so far is here: http://stackoverflow.com/questions/33112559/protocol-doesnt-conform-to-itself/33524927#33524927)

Here is the best you can do for your particular use case:

protocol AnyEquatable { func equals(other: Any) -> Bool }

func ==<T: Equatable>(lhs: T, rhs: Any) -> Bool {
    
    if let rhs = rhs as? T { return lhs == rhs } else { return false }
}

extension Bool: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension Int: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension Double: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension String: AnyEquatable { func equals(other: Any) -> Bool { return self == other } }

extension Array {
    
    func indexOfAny(element : AnyEquatable) -> Index? { return indexOf { element.equals($0) } }
}

var array: [Any] = [false, 1, 2.0, "three"]

array.indexOfAny(2.0)

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users