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