Usage of Generics - swift

I have the following structs:
struct A<T> {
var val: T
}
struct B<T> {
var setOfA: Set<A<T>>
}
Is this incorrect usage of generics, if the set of As can have values of both A<Int> and A<Float> type (or any other type)?
If yes, is using Any the correct way to do this?
Would generics have been the right way to go, if the set of As was constrained to A<>s of a single type?

Swift is a moving target, all code tested using Xcode 9.2 & Swift 4.0.
First if you wish to insert A<T> items into a set then the type must implement the Hashable protocol. You can implement this protocol as needed but for illustrative purposes a simple approach is to require the type parameter T to be Hashable and to implement the protocol by indirecting to val:
struct A<T> : Hashable where T : Hashable
{
var val : T
var hashValue: Int { return val.hashValue }
static func ==(lhs: A<T>, rhs: A<T>) -> Bool
{
return lhs.val == rhs.val
}
}
The rest of the answer does not require the above implementation, just that A<T> is Hashable.
Constraining your Set to only containing instances of A<T> for any and all T is more of a challenge. One approach to this problem is to use an existential type, which in this context essentially allows the wrapping of differently typed value inside another non-generic wrapper. Swift has some pre-defined existential types, in particular AnyHashable which you could use to define B's var:
struct B
{
var setOfA : Set<AnyHashable> = Set()
...
}
Unfortunately this does not constrain the set to only hold values of type A<T> for any T.
The type of setOfA cannot be Set<A<AnyHashable>> as that would require a value of type A<T> for some T to be cast-able to A<AnyHashable> and Swift does not support that (researching variance might help understand why).
You might wonder why the type cannot be Set<Hashable>. Unfortunately (in this context!) Hashable is a protocol with a Self requirement and Swift does not support using it as a generic type parameter in this context. AnyHashable is a non-generic struct which type erases (the existential type bit) the value it wraps.
So back to solving the problem of constraining the set to only contains A's. One solution is to hide (private) the set inside B and provide a generic insertion function which only accepts A<T> values, for any T. The set value itself can then be made public using a read-only computed property. For example:
struct B
{
// private property so only B's functions can modify the set
private var _setOfA : Set<AnyHashable> = Set()
// public read-only property so _setOfA cannot be changed directly
var setOfA : Set<AnyHashable> { return _setOfA }
// public insert function which only accepts A<T> values, for any T
mutating func insert<T>(_ element : A<T>) -> (Bool, A<T>)
{
return _setOfA.insert(element)
}
}
Here is dome sample code using the above:
let x = A(val: 4) // x : A<Int>
let y = A(val: "hello") // y : A<String>
var z = B()
print(z.insert(x)) // insert being generic accepts any A<T>
print(z.insert(y))
print(z.insert(x)) // should return (false, x) as element already added
print("\(z)")
for member in z.setOfA
{
print("member = \(member) : \(type(of:member))")
if let intMember = member as? A<Int>
{
print(" intMember = \(intMember) : \(type(of:intMember))")
}
else if let stringMember = member as? A<String>
{
print(" stringMember = \(stringMember) : \(type(of:stringMember))")
}
}
This outputs:
(true, __lldb_expr_501.A<Swift.Int>(val: 4))
(true, __lldb_expr_501.A<Swift.String>(val: "hello"))
(false, __lldb_expr_501.A<Swift.Int>(val: 4))
B(_setOfA: Set([AnyHashable(__lldb_expr_501.A<Swift.String>(val: "hello")), AnyHashable(__lldb_expr_501.A<Swift.Int>(val: 4))]))
member = A<String>(val: "hello") : AnyHashable
stringMember = A<String>(val: "hello") : A<String>
member = A<Int>(val: 4) : AnyHashable
intMember = A<Int>(val: 4) : A<Int>
HTH

If you plan on letting your struct contain val of a specific type, use <T: DesiredProtocol>. If the type doesn't matter, and your val can be of any type, just implement the structure as struct A<T> {}. A<T> is equal to A<T: Any>.
Note that your example won't compile if you intend to have setOfA contain A with different types.
The elements in a Set must be hashable.
In B<T>, T represents only one type. Therefore, you cannot store different types in Set<A<T>>.
Because of this requirement, struct A<T> must conform to the Hashable protocol, and the implementation of B must be changed.
struct A<T>: Hashable {
var val: T
// Implementation of Hashable
}
/// This struct should not be generic. It would constrain its setOfA to only contain the same type.
/// By removing the generics, and use Any instead, you let each element have its own type.
struct B {
var setOfA: Set<A<Any>>
}
var set: Set<A<Any>> = Set()
set.insert(A(val: 0 as Int))
set.insert(A(val: 1 as Float))
let b = B(setOfA: set)
Edit:
Due to the fact that you're looking for a way to insert a generic A<T> into A<Any> without specifying its type as A<Any> on creation, I've come up with two different ways:
let v1 = A(val: 5)
var v2 = A(val: 3)
aSet.insert(A(val: v2.val))
aSet.insert(withUnsafePointer(to: &v3, { return UnsafeRawPointer($0) }).assumingMemoryBound(to: A<Any>.self).pointee)
Edit
If it is as you write, that B's setOfA would only have A<> of a single type, it's the choice of the context whether you should use generics or not. The question is rather if struct B needs to be generic. struct A can be a value type for many different tasks, while struct B doesn't need to. If B is more specific, you could rather just write:
struct B {
var setOfA: Set<A<Int>>
}
As above-mentioned, if you intend to have the same set contain A<Int> and A<Float>, then var setOfA: Set<A<Any>> is the correct way.
If struct A has a very specific use-case, and you don't actually need it to be generic, you should change the type of val. Your code should be understandable and comprehensive. I would recommend one of these solutions:
struct A: Hashable {
var val: Any
// or
var val: Numeric
// Implementation of Hashable
}

Related

Cannot assign value of type CustomViewcontroller<FirstModel> to type CustomViewcontroller<SecondModel> [duplicate]

I'm using Signals library.
Let's say I defined BaseProtocol protocol and ChildClass which conforms BaseProtocol.
protocol BaseProtocol {}
class ChildClass: BaseProtocol {}
Now I want to store signals like:
var signals: Array<Signal<BaseProtocol>> = []
let signalOfChild = Signal<ChildClass>()
signals.append(signalOfChild)
I get error:
But I can write next lines without any compiler error:
var arrays = Array<Array<BaseProtocol>>()
let arrayOfChild = Array<ChildClass>()
arrays.append(arrayOfChild)
So, what the difference between generic Swift Array and generic Signal?
The difference is that Array (and Set and Dictionary) get special treatment from the compiler, allowing for covariance (I go into this in slightly more detail in this Q&A).
However arbitrary generic types are invariant, meaning that X<T> is a completely unrelated type to X<U> if T != U – any other typing relation between T and U (such as subtyping) is irrelevant. Applied to your case, Signal<ChildClass> and Signal<BaseProtocol> are unrelated types, even though ChildClass is a subtype of BaseProtocol (see also this Q&A).
One reason for this is it would completely break generic reference types that define contravariant things (such as function parameters and property setters) with respect to T.
For example, if you had implemented Signal as:
class Signal<T> {
var t: T
init(t: T) {
self.t = t
}
}
If you were able to say:
let signalInt = Signal(t: 5)
let signalAny: Signal<Any> = signalInt
you could then say:
signalAny.t = "wassup" // assigning a String to a Signal<Int>'s `t` property.
which is completely wrong, as you cannot assign a String to an Int property.
The reason why this kind of thing is safe for Array is that it's a value type – thus when you do:
let intArray = [2, 3, 4]
var anyArray : [Any] = intArray
anyArray.append("wassup")
there are no problems, as anyArray is a copy of intArray – thus the contravariance of append(_:) is not a problem.
However, this cannot be applied to arbitrary generic value types, as value types can contain any number of generic reference types, which leads us back down the dangerous road of allowing an illegal operation for generic reference types that define contravariant things.
As Rob says in his answer, the solution for reference types, if you need to maintain a reference to the same underlying instance, is to use a type-eraser.
If we consider the example:
protocol BaseProtocol {}
class ChildClass: BaseProtocol {}
class AnotherChild : BaseProtocol {}
class Signal<T> {
var t: T
init(t: T) {
self.t = t
}
}
let childSignal = Signal(t: ChildClass())
let anotherSignal = Signal(t: AnotherChild())
A type-eraser that wraps any Signal<T> instance where T conforms to BaseProtocol could look like this:
struct AnyBaseProtocolSignal {
private let _t: () -> BaseProtocol
var t: BaseProtocol { return _t() }
init<T : BaseProtocol>(_ base: Signal<T>) {
_t = { base.t }
}
}
// ...
let signals = [AnyBaseProtocolSignal(childSignal), AnyBaseProtocolSignal(anotherSignal)]
This now lets us talk in terms of heterogenous types of Signal where the T is some type that conforms to BaseProtocol.
However one problem with this wrapper is that we're restricted to talking in terms of BaseProtocol. What if we had AnotherProtocol and wanted a type-eraser for Signal instances where T conforms to AnotherProtocol?
One solution to this is to pass a transform function to the type-eraser, allowing us to perform an arbitrary upcast.
struct AnySignal<T> {
private let _t: () -> T
var t: T { return _t() }
init<U>(_ base: Signal<U>, transform: #escaping (U) -> T) {
_t = { transform(base.t) }
}
}
Now we can talk in terms of heterogenous types of Signal where T is some type that's convertible to some U, which is specified at the creation of the type-eraser.
let signals: [AnySignal<BaseProtocol>] = [
AnySignal(childSignal, transform: { $0 }),
AnySignal(anotherSignal, transform: { $0 })
// or AnySignal(childSignal, transform: { $0 as BaseProtocol })
// to be explicit.
]
However, the passing of the same transform function to each initialiser is a little unwieldy.
In Swift 3.1 (available with Xcode 8.3 beta), you can lift this burden from the caller by defining your own initialiser specifically for BaseProtocol in an extension:
extension AnySignal where T == BaseProtocol {
init<U : BaseProtocol>(_ base: Signal<U>) {
self.init(base, transform: { $0 })
}
}
(and repeat for any other protocol types you want to convert to)
Now you can just say:
let signals: [AnySignal<BaseProtocol>] = [
AnySignal(childSignal),
AnySignal(anotherSignal)
]
(You can actually remove the explicit type annotation for the array here, and the compiler will infer it to be [AnySignal<BaseProtocol>] – but if you're going to allow for more convenience initialisers, I would keep it explicit)
The solution for value types, or reference types where you want to specifically create a new instance, to is perform a conversion from Signal<T> (where T conforms to BaseProtocol) to Signal<BaseProtocol>.
In Swift 3.1, you can do this by defining a (convenience) initialiser in an extension for Signal types where T == BaseProtocol:
extension Signal where T == BaseProtocol {
convenience init<T : BaseProtocol>(other: Signal<T>) {
self.init(t: other.t)
}
}
// ...
let signals: [Signal<BaseProtocol>] = [
Signal(other: childSignal),
Signal(other: anotherSignal)
]
Pre Swift 3.1, this can be achieved with an instance method:
extension Signal where T : BaseProtocol {
func asBaseProtocol() -> Signal<BaseProtocol> {
return Signal<BaseProtocol>(t: t)
}
}
// ...
let signals: [Signal<BaseProtocol>] = [
childSignal.asBaseProtocol(),
anotherSignal.asBaseProtocol()
]
The procedure in both cases would be similar for a struct.

Declare an array of a generic struct specialized with different types

I know that Swift does not have wildcard types to specialize generic types. I have a problem I would know how to solve using them in a language like Java.
In the following example I'm trying to define a struct Property which encapsulates access to a property of a type T to perform two operations, getting the hash value of the value of that property on an instance of T and comparing the values of the property on two instances of T. To allow this, the struct contains a property getter holding a function which returns the value of the specific property on an instance. Because of this, the struct needs to be generic not only in T but also the type E of the property.
In the struct Test, I would like to define a static property properties holding an array of Property instances, one for each property of Test. I cannot see a way to do that because I don't know what type to use for properties or how to "hide" the type parameter E so that it does not need to be specified in the declaration of properties.
// Struct which represents a property of type T with a value of type E.
// Aside from initialization only T is visible from outside.
public struct Property<T, E: Hashable> {
let getter: (T) -> E
func getMemberHashValue(instance: T) -> Int {
return getter(instance).hashValue
}
func equalsMembers(instance1: T, instance2: T) -> Bool {
return getter(instance1) == getter(instance2)
}
}
struct Test {
// Some properties with different types
let a: Int
let b: Double
// Array of Property instances for all properties of Test.
// Not valid syntax.
let properties: [Property<Test, ?>] = [
Property(getter: { (instance: Test) in instance.a }),
Property(getter: { (instance: Test) in instance.b })]
}
I know that I could in this case substitute AnyHashable for the second type parameter in the declaration of properties as it has no associated types, but I would like to find a general solution I could apply in cases not involving Hashable.
Is there a way to change this example to allow such a property properties to be defined holding multiple Property instances for properties of different types?
Overview:
I am not sure I understood your question correctly.
Might be worth stating why you would like a heterogeneous array, would lose all type safety in the process.
Might be revisiting the design
Option 1:
If it is absolutely required, if so just use an NSArray / NSMutableArray
Option 2:
If you want to access properties of a class / struct / enum dynamically, you could do so with KeyPath.
Code:
struct Test : Hashable {
// Some properties with different types
let a: Int
let b: Double
let c: String
//This function will return any property of Test instance
func property<T>(forKeyPath keyPath: KeyPath<Test, T>) -> T {
return self[keyPath: keyPath]
}
//MARK: Hashable
var hashValue: Int {
return a.hashValue ^ b.hashValue ^ c.hashValue
}
//MARK: Equatable
static func ==(lhs: Test, rhs: Test) -> Bool {
return lhs.a == rhs.a &&
lhs.b == rhs.b &&
lhs.c == rhs.c
}
}
let test1 = Test(a: 10, b: 22.22, c: "aaaa")
let cValue = test1.property(forKeyPath: \.c) //aaaa
let cHashValue = test1.property(forKeyPath: \.c.hashValue) //Hash value of aaaa
let someInt = 10 //This is also Hashable
var mixedArray = [AnyHashable]()
mixedArray.append(test1)
mixedArray.append(someInt)
Refer:
If this matches your requirement, then please read about KeyPath, PartialKeyPath.
Version:
Swift 4

cast generic type to the type with Any as the type parameter [duplicate]

I'm using Signals library.
Let's say I defined BaseProtocol protocol and ChildClass which conforms BaseProtocol.
protocol BaseProtocol {}
class ChildClass: BaseProtocol {}
Now I want to store signals like:
var signals: Array<Signal<BaseProtocol>> = []
let signalOfChild = Signal<ChildClass>()
signals.append(signalOfChild)
I get error:
But I can write next lines without any compiler error:
var arrays = Array<Array<BaseProtocol>>()
let arrayOfChild = Array<ChildClass>()
arrays.append(arrayOfChild)
So, what the difference between generic Swift Array and generic Signal?
The difference is that Array (and Set and Dictionary) get special treatment from the compiler, allowing for covariance (I go into this in slightly more detail in this Q&A).
However arbitrary generic types are invariant, meaning that X<T> is a completely unrelated type to X<U> if T != U – any other typing relation between T and U (such as subtyping) is irrelevant. Applied to your case, Signal<ChildClass> and Signal<BaseProtocol> are unrelated types, even though ChildClass is a subtype of BaseProtocol (see also this Q&A).
One reason for this is it would completely break generic reference types that define contravariant things (such as function parameters and property setters) with respect to T.
For example, if you had implemented Signal as:
class Signal<T> {
var t: T
init(t: T) {
self.t = t
}
}
If you were able to say:
let signalInt = Signal(t: 5)
let signalAny: Signal<Any> = signalInt
you could then say:
signalAny.t = "wassup" // assigning a String to a Signal<Int>'s `t` property.
which is completely wrong, as you cannot assign a String to an Int property.
The reason why this kind of thing is safe for Array is that it's a value type – thus when you do:
let intArray = [2, 3, 4]
var anyArray : [Any] = intArray
anyArray.append("wassup")
there are no problems, as anyArray is a copy of intArray – thus the contravariance of append(_:) is not a problem.
However, this cannot be applied to arbitrary generic value types, as value types can contain any number of generic reference types, which leads us back down the dangerous road of allowing an illegal operation for generic reference types that define contravariant things.
As Rob says in his answer, the solution for reference types, if you need to maintain a reference to the same underlying instance, is to use a type-eraser.
If we consider the example:
protocol BaseProtocol {}
class ChildClass: BaseProtocol {}
class AnotherChild : BaseProtocol {}
class Signal<T> {
var t: T
init(t: T) {
self.t = t
}
}
let childSignal = Signal(t: ChildClass())
let anotherSignal = Signal(t: AnotherChild())
A type-eraser that wraps any Signal<T> instance where T conforms to BaseProtocol could look like this:
struct AnyBaseProtocolSignal {
private let _t: () -> BaseProtocol
var t: BaseProtocol { return _t() }
init<T : BaseProtocol>(_ base: Signal<T>) {
_t = { base.t }
}
}
// ...
let signals = [AnyBaseProtocolSignal(childSignal), AnyBaseProtocolSignal(anotherSignal)]
This now lets us talk in terms of heterogenous types of Signal where the T is some type that conforms to BaseProtocol.
However one problem with this wrapper is that we're restricted to talking in terms of BaseProtocol. What if we had AnotherProtocol and wanted a type-eraser for Signal instances where T conforms to AnotherProtocol?
One solution to this is to pass a transform function to the type-eraser, allowing us to perform an arbitrary upcast.
struct AnySignal<T> {
private let _t: () -> T
var t: T { return _t() }
init<U>(_ base: Signal<U>, transform: #escaping (U) -> T) {
_t = { transform(base.t) }
}
}
Now we can talk in terms of heterogenous types of Signal where T is some type that's convertible to some U, which is specified at the creation of the type-eraser.
let signals: [AnySignal<BaseProtocol>] = [
AnySignal(childSignal, transform: { $0 }),
AnySignal(anotherSignal, transform: { $0 })
// or AnySignal(childSignal, transform: { $0 as BaseProtocol })
// to be explicit.
]
However, the passing of the same transform function to each initialiser is a little unwieldy.
In Swift 3.1 (available with Xcode 8.3 beta), you can lift this burden from the caller by defining your own initialiser specifically for BaseProtocol in an extension:
extension AnySignal where T == BaseProtocol {
init<U : BaseProtocol>(_ base: Signal<U>) {
self.init(base, transform: { $0 })
}
}
(and repeat for any other protocol types you want to convert to)
Now you can just say:
let signals: [AnySignal<BaseProtocol>] = [
AnySignal(childSignal),
AnySignal(anotherSignal)
]
(You can actually remove the explicit type annotation for the array here, and the compiler will infer it to be [AnySignal<BaseProtocol>] – but if you're going to allow for more convenience initialisers, I would keep it explicit)
The solution for value types, or reference types where you want to specifically create a new instance, to is perform a conversion from Signal<T> (where T conforms to BaseProtocol) to Signal<BaseProtocol>.
In Swift 3.1, you can do this by defining a (convenience) initialiser in an extension for Signal types where T == BaseProtocol:
extension Signal where T == BaseProtocol {
convenience init<T : BaseProtocol>(other: Signal<T>) {
self.init(t: other.t)
}
}
// ...
let signals: [Signal<BaseProtocol>] = [
Signal(other: childSignal),
Signal(other: anotherSignal)
]
Pre Swift 3.1, this can be achieved with an instance method:
extension Signal where T : BaseProtocol {
func asBaseProtocol() -> Signal<BaseProtocol> {
return Signal<BaseProtocol>(t: t)
}
}
// ...
let signals: [Signal<BaseProtocol>] = [
childSignal.asBaseProtocol(),
anotherSignal.asBaseProtocol()
]
The procedure in both cases would be similar for a struct.

In Swift, how to cast to protocol with associated type?

In the following code, I want to test if x is a SpecialController. If it is, I want to get the currentValue as a SpecialValue. How do you do this? If not with a cast, then some other technique.
The last line there won't compile. There error is: Protocol "SpecialController" can only be used as a generic constraint because it has Self or associated type requirements.
protocol SpecialController {
associatedtype SpecialValueType : SpecialValue
var currentValue: SpecialValueType? { get }
}
...
var x: AnyObject = ...
if let sc = x as? SpecialController { // does not compile
Unfortunately, Swift doesn't currently support the use of protocols with associated types as actual types. This however is technically possible for the compiler to do; and it may well be implemented in a future version of the language.
A simple solution in your case is to define a 'shadow protocol' that SpecialController derives from, and allows you to access currentValue through a protocol requirement that type erases it:
// This assumes SpecialValue doesn't have associated types – if it does, you can
// repeat the same logic by adding TypeErasedSpecialValue, and then using that.
protocol SpecialValue {
// ...
}
protocol TypeErasedSpecialController {
var typeErasedCurrentValue: SpecialValue? { get }
}
protocol SpecialController : TypeErasedSpecialController {
associatedtype SpecialValueType : SpecialValue
var currentValue: SpecialValueType? { get }
}
extension SpecialController {
var typeErasedCurrentValue: SpecialValue? { return currentValue }
}
extension String : SpecialValue {}
struct S : SpecialController {
var currentValue: String?
}
var x: Any = S(currentValue: "Hello World!")
if let sc = x as? TypeErasedSpecialController {
print(sc.typeErasedCurrentValue as Any) // Optional("Hello World!")
}
[Edited to fix: : SpecialValue, not = SpecialValue]
This is not possible. SpecialValueController is an "incomplete type" conceptually so the compiler cannot know. SpecialValueType, although it is constrained by SpecialValue, it is not known until it is determined by any adopting class. So it is a really placeholder with inadequate information. as?-ness cannot be checked.
You could have a base class that adopts SpecialController with a concrete type for SpecialValueController, and have multiple child classes that inherit from the adopting class, if you're still seeking a degree of polymorphism.
This doesn't work because SpecialController isn't a single type. You can think of associated types as a kind of generics. A SpecialController with its SpecialValueType being an Int is a completely different type from a SpecialController with its SpecialValueType being an String, just like how Optional<Int> is a completely different type from Optional<String>.
Because of this, it doesn't make any sense to cast to SpecialValueType, because that would gloss over the associated type, and allow you to use (for example) a SpecialController with its SpecialValueType being an Int where a SpecialController with its SpecialValueType being a String is expected.
As compiler suggests, the only way SpecialController can be used is as a generic constraint. You can have a function that's generic over T, with the constraint that T must be a SpecialController. The domain of T now spans all the various concrete types of SpecialController, such as one with an Int associated type, and one with a String. For each possible associated type, there's a distinct SpecialController, and by extension, a distinct T.
To draw out the Optional<T> analogy further. Imagine if what you're trying to do was possible. It would be much like this:
func funcThatExpectsIntOptional(_: Int?) {}
let x: Optional<String> = "An optional string"
// Without its generic type parameter, this is an incomplete type. suppose this were valid
let y = x as! Optional
funcThatExpectsIntOptional(y) // boom.

How to create Dictionary that can hold anything in Key? or all the possible type it capable to hold

I want to create a Dictionary that does not limit the key type (like NSDictionary)
So I tried
var dict = Dictionary<Any, Int>()
and
var dict = Dictionary<AnyObject, Int>()
resulting
error: type 'Any' does not conform to protocol 'Hashable'
var dict = Dictionary<Any, Int>()
^
<REPL>:5:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<Any, Int>()
^~~~~~~~~~~~~~~~~~~~~~
OK, I will use Hashable
var dict = Dictionary<Hashable, Int>()
but
error: type 'Hashable' does not conform to protocol 'Equatable'
var dict = Dictionary<Hashable, Int>()
^
Swift.Equatable:2:8: note: '==' requirement refers to 'Self' type
func ==(lhs: Self, rhs: Self) -> Bool
^
Swift.Hashable:1:10: note: type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol'
protocol Hashable : Equatable
^
<REPL>:5:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<Hashable, Int>()
^~~~~~~~~~~~~~~~~~~~~~~~~~~
So Hashable inherited from Equatable but it does not conform to Equatable??? I don't understand...
Anyway, keep trying
typealias KeyType = protocol<Hashable, Equatable> // KeyType is both Hashable and Equatable
var dict = Dictionary<KeyType, Int>() // now you happy?
with no luck
error: type 'KeyType' does not conform to protocol 'Equatable'
var dict = Dictionary<KeyType, Int>()
^
Swift.Equatable:2:8: note: '==' requirement refers to 'Self' type
func ==(lhs: Self, rhs: Self) -> Bool
^
Swift.Hashable:1:10: note: type 'KeyType' does not conform to inherited protocol 'Equatable.Protocol'
protocol Hashable : Equatable
^
<REPL>:6:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<KeyType, Int>()
^~~~~~~~~~~~~~~~~~~~~~~~~~
I am so lost now, how can I make compiler happy with my code?
I want to use the dictionary like
var dict = Dictionary<Any, Int>()
dict[1] = 2
dict["key"] = 3
dict[SomeEnum.SomeValue] = 4
I know I can use Dictionary<NSObject, Int>, but it is not really what I want.
Swift 3 update
You can now use AnyHashable which is a type-erased hashable value, created exactly for scenarios like this:
var dict = Dictionary<AnyHashable, Int>()
I believe that, as of Swift 1.2, you can use an ObjectIdentifier struct for this. It implements Hashable (and hence Equatable) as well as Comparable. You can use it to wrap any class instance. I'm guessing the implementation uses the wrapped object's underlying address for the hashValue, as well as within the == operator.
I took the liberty of cross-posting / linking to this question on a separate post on the Apple Dev forums and this question is answered here.
Edit
This answer from the above link works in 6.1 and greater:
struct AnyKey: Hashable {
private let underlying: Any
private let hashValueFunc: () -> Int
private let equalityFunc: (Any) -> Bool
init<T: Hashable>(_ key: T) {
underlying = key
// Capture the key's hashability and equatability using closures.
// The Key shares the hash of the underlying value.
hashValueFunc = { key.hashValue }
// The Key is equal to a Key of the same underlying type,
// whose underlying value is "==" to ours.
equalityFunc = {
if let other = $0 as? T {
return key == other
}
return false
}
}
var hashValue: Int { return hashValueFunc() }
}
func ==(x: AnyKey, y: AnyKey) -> Bool {
return x.equalityFunc(y.underlying)
}
Dictionary is struct Dictionary<Key : Hashable, Value>...
Which means that Value could be anything you want, and Key could be any type you want, but Key must conform to Hashable protocol.
You can't create Dictionary<Any, Int>() or Dictionary<AnyObject, Int>(), because Any and AnyObject can't guarantee that such a Key conforms Hashable
You can't create Dictionary<Hashable, Int>(), because Hashable is not a type it is just protocol which is describing needed type.
So Hashable inherited from Equatable but it does not conform to
Equatable??? I don't understand...
But you are wrong in terminology. Original error is
type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol'
That means that Xcode assuming 'Hashable' as some type, but there is no such type. And Xcode treat it as some kind empty type, which obviously does not conform any protocol at all (in this case it does not conform to inherited protocol Equatable)
Something similar happens with KeyType.
A type alias declaration introduces a named alias of an existing type into your program.
You see existing type. protocol<Hashable, Equatable> is not a type it is protocol so Xcode again tells you that type 'KeyType' does not conform to protocol 'Equatable'
You can use Dictionary<NSObject, Int> just, because NSObject conforms Hashable protocol.
Swift is strong typing language and you can't do some things like creating Dictionary that can hold anything in Key. Actually dictionary already supports any can hold anything in Key, which conforms Hashable. But since you should specify particular class you can't do this for native Swift classes, because there is no such master class in Swift like in Objective-C, which conforms air could conform (with a help of extensions) to Hashable
Of course you can use some wrapper like chrisco suggested. But I really can't imagine why you need it. It is great that you have strong typing in Swift so you don't need to worry about types casting as you did in Objective-C
Hashable is just a protocol so you can't specify it directly as a type for the Key value. What you really need is a way of expressing "any type T, such that T implements Hashable. This is handled by type constraints in Swift:
func makeDict<T: Hashable>(arr: T[]) {
let x = Dictionary<T, Int>()
}
This code compiles.
AFAIK, you can only use type constraints on generic functions and classes.
This doesn't exactly answer the question, but has helped me.
The general answer would be implement Hashable for all your types, however that can be hard for Protocols because Hashable extends Equatable and Equatable uses Self which imposes severe limitations on what a protocol can be used for.
Instead implement Printable and then do:
var dict = [String: Int]
dict[key.description] = 3
The implementation of description has to be something like:
var description : String {
return "<TypeName>[\(<Field1>), \(<Field2>), ...]"
}
Not a perfect answer, but the best I have so far :(
This does not answer the OP's question, but is somewhat related, and may hopefully be of use for some situations. Suppose that what you really want to do is this:
public var classTypeToClassNumber = [Any.Type : Int]()
But Swift is telling you "Type 'Any.Type' does not conform to protocol Hashable".
Most of the above answers are about using object instances as a dictionary key, not using the type of the object. (Which is fair enough, that's what the OP was asking about.) It was the answer by Howard Lovatt that led me to a usable solution.
public class ClassNumberVsClassType {
public var classTypeToClassNumber = [String : Int]()
public init() {
classTypeToClassNumber[String(describing: ClassWithStringKey.self)] = 367622
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList3.self)] = 367629
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList2.self)] = 367626
classTypeToClassNumber[String(describing: ClassWithGuidKey.self)] = 367623
classTypeToClassNumber[String(describing: SimpleStruct.self)] = 367619
classTypeToClassNumber[String(describing: TestData.self)] = 367627
classTypeToClassNumber[String(describing: ETestEnum.self)] = 367617
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList0.self)] = 367624
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList1.self)] = 367625
classTypeToClassNumber[String(describing: SimpleClass.self)] = 367620
classTypeToClassNumber[String(describing: DerivedClass.self)] = 367621
}
public func findClassNumber(_ theType : Any.Type) -> Int {
var s = String(describing: theType)
if s.hasSuffix(".Type") {
s = s.substring(to: s.index(s.endIndex, offsetBy: -5)) // Remove ".Type"
}
let classNumber = _classTypeToClassNumber[s]
return classNumber != nil ? classNumber! : -1
}
}
EDIT:
If the classes involved are defined in different modules, and may have conflicting class names if you neglect the module name, then substitute "String(reflecting:" for "String(describing:", both when building up the dictionary and when doing the lookup.
You can use the class name as a Hashable, e.g.:
var dict = [String: Int]
dict[object_getClassName("key")] = 3
See How do I print the type or class of a variable in Swift? for how you might get the class name.