swift: AnyCollection with different generic types - swift

AnyCollection([1, 2, 3]) // AnyCollection<Int>
AnyCollection(["a", "b", "c"]) // AnyCollection<String>
These two AnyCollection is great, but they have different Generic types, namely Int and String.
But I can still add these two AnyCollection to a single array, like this
// [AnyCollection<Any>]
let array = [AnyCollection([1, 2, 3]), AnyCollection(["a", "b", "c"])]
I can't understand what happened to these two AnyCollection.
Why can it convert from String or Int to Any ??
I wrote some code to create one myself.
// ❌ Heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional
// Contains AnyMyCollection<String> && AnyMyCollection<Int> at a single collection.
var collections = [AnyMyCollection(Sports()), AnyMyCollection(Animals()), AnyMyCollection(Digits())]
protocol MyCollection<Element> {
associatedtype Element
func allValues() -> [Element]
}
// MARK: - AnyMyCollection
struct AnyMyCollection<Element> {
internal var _box: _AnyMyCollectionBase<Element>
init<C: MyCollection>(_ base: C) where C.Element == Element {
self._box = _MyCollectionBox(base)
}
}
extension AnyMyCollection: MyCollection {
func allValues() -> [Element] {
_box.allValues()
}
}
final class _MyCollectionBox<Base: MyCollection>: _AnyMyCollectionBase<Base.Element> {
init(_ base: Base) {
_base = base
}
private var _base: Base
override func allValues() -> [Base.Element] {
_base.allValues()
}
}
class _AnyMyCollectionBase<Element>: MyCollection {
func allValues() -> [Element] {
return []
}
}
// MARK: - Diffrent Types of My Collection
struct Animals: MyCollection {
typealias Element = String
func allValues() -> [Element] {
["Monkey", "Tiger", "Lion"]
}
}
struct Sports: MyCollection {
typealias Element = String
func allValues() -> [Element] {
["Basketball", "Football", "Baseball"]
}
}
struct Digits: MyCollection {
typealias Element = Int
func allValues() -> [Element] {
[1, 2, 3, 4, 5]
}
}
I tried to follow the same technique but failed because the type of the element in AnyMyCollection is not the same.

The simple explanation is that you are not Apple.
Generics in general are not covariant over the parameterized type, and you have no way to create to generic that is covariant over the paramterized type. But Apple does.
To see this more simply, consider Array. It is a generic. If you have two classes, a class and its subclass, you can combine arrays of each of them:
class MyClass {}
class MySubclass: MyClass {}
let arr1 = [MyClass()]
let arr2 = [MySubclass()]
let arr3 = [arr1, arr2] // [[MyClass]]
The compiler accepts this; it treats the resulting combination as an array of arrays of the superclass, Array<Array<MyClass>>. So for Apple, an Array<MySubclass> is treated as a sort of subclass of Array<MyClass>.
But now try to do that with your own generic. You can't do it:
class MyGeneric<T> {}
let g1 = MyGeneric<MyClass>()
let g2 = MyGeneric<MySubclass>()
let arr4 = [g1, g2] // error
The compiler does not magically see this as an Array<MyGeneric<MyClass>>. That's because your generic is not covariant.
There are always language proposals sitting around, hoping to allow us ordinary human beings to make covariant generics. But so far, none of them has arrived into the language.

Related

Swift couldn't infer generic type when I was trying to provide my own implementation of AnySequence

The problem is when one protocol depends on another through its associated type, compiler isn't able to infer generic types.
So, I was playing around with Swift's type erasure technique trying to become familiar with its idea. Basically it'd been pretty understandable until I got to Sequence protocol. It's known that it has an associated type - Iterator, which conforms IteratorProtocol. That said, I've been trying to achieve similar behavior in my own implementation. That's what I've done:
final class CustomAnySequence<Element>: Sequence {
class CustomAnyIterator<Element>: IteratorProtocol {
private let _next: () -> Element?
init<I: IteratorProtocol>(_ iterator: I) where I.Element == Element {
var iterator = iterator
_next = { iterator.next() }
}
func next() -> Element? {
return _next()
}
}
typealias Iterator = CustomAnyIterator<Element>
typealias Element = Iterator.Element
private let _makeIterator: () -> Iterator
init<S: Sequence>(_ sequence: S) where S.Iterator == Iterator {
_makeIterator = sequence.makeIterator
}
func makeIterator() -> Iterator {
return _makeIterator()
}
}
let sequence = CustomAnySequence([1, 2, 3])
So, the last line gives the following error: Generic parameter 'Element' could not be inferred.
Then if I try to fix it by explicitly specifying Element type:
let sequence = CustomAnySequence<Int>([1, 2, 3])
it's not making it better. The next Xcode complaint is: Generic parameter 'S' could not be inferred.
So is there my fault, or it's just too much overhead for Swift's type inference?
Actually, I've run into another possible implementation - it's using private subclass wrapping. I don't really like it (that's why I was trying to do it on my own) because there are "fatal-error-must-be-subclassed" methods in superclass's implementations, which don't contribute to clean code. Also, I'm not sure how I could implement this functionality by the initializer of CustomAnySequence (I've only found it possible by making a static method). Despite all that, that's the code:
class CustomAnySequence<Element>: Sequence {
class Iterator: IteratorProtocol {
func next() -> Element? {
fatalError("Must be overriden")
}
}
func makeIterator() -> Iterator {
fatalError("Must be overriden")
}
}
private final class CustomAnySequenceImplementation<S: Sequence>: CustomAnySequence<S.Element> {
final class IteratorImplementation: Iterator {
var wrapped: S.Iterator
init(_ wrapped: S.Iterator) {
self.wrapped = wrapped
}
override func next() -> S.Element? {
return wrapped.next()
}
}
var sequence: S
init(_ sequence: S) {
self.sequence = sequence
}
override func makeIterator() -> IteratorImplementation {
return IteratorImplementation(sequence.makeIterator())
}
}
extension CustomAnySequence {
static func make<S: Sequence>(_ sequence: S) -> CustomAnySequence<Element> where S.Element == Element {
return CustomAnySequenceImplementation<S>(sequence)
}
}
func printInts(_ sequence: CustomAnySequence<Int>) {
for element in sequence {
print(element)
}
}
printInts(CustomAnySequence.make([1, 2, 3]))
printInts(CustomAnySequence.make(Set([4, 5, 6])))
It actually does work, but it looks a bit like a boilerplate. At least, if you realize how to improve it by using an initializer, please let me know. Thank you in advance!
The problem with the first implementation is that
let sequence = CustomAnySequence([1, 2, 3])
does not satisfy the constraint in
init<S: Sequence>(_ sequence: S) where S.Iterator == Iterator
[1, 2, 3] is a sequence, but its iterator type is not your CustomAnyIterator. What you really want is to pass a sequence with the same element type, not the same iterator type:
init<S: Sequence>(_ sequence: S) where S.Element == Element
and pass sequence.makeIterator() to the init method of CustomAnyIterator.
Note also the inner class can inherit the Element type placeholder from the outer class, and that the type aliases are not really needed.
final class CustomAnySequence<Element>: Sequence {
class CustomAnyIterator: IteratorProtocol {
private let _next: () -> Element?
init<I: IteratorProtocol>(_ iterator: I) where I.Element == Element {
var iterator = iterator
_next = { iterator.next() }
}
func next() -> Element? {
return _next()
}
}
private let _makeIterator: () -> CustomAnyIterator
init<S: Sequence>(_ sequence: S) where S.Element == Element {
_makeIterator = { CustomAnyIterator(sequence.makeIterator()) }
}
func makeIterator() -> CustomAnyIterator {
return _makeIterator()
}
}
You may also consider to use a struct instead of a class.

Using Class Type as Dictionary Key [duplicate]

I'm trying to do this sort of thing ..
static var recycle: [Type: [CellThing]] = []
but - I can't :)
Undeclared type 'Type'
In the example, CellThing is my base class, so A:CellThing, B:CellThing, C:CellThing and so on. The idea is I would store various A A A, B B, C C C C in the dictionary arrays.
How to make a "Type" (ideally I guess, constrained to CellThing) be the key in a Swift dictionary?
I appreciate I could (perhaps?) use String(describing: T.self), but that would make me lose sleep.
Here's a use case, envisaged code would look something like this ...
#discardableResult class func make(...)->Self {
return makeHelper(...)
}
private class func makeHelper<T: CellThing>(...)->T {
let c = instantiateViewController(...) as! T
return c
}
So then something like ...
static var recycle: [Type: [CellThing]] = []
private class func makeHelper<T: CellThing>(...)->T {
let c = instantiateViewController(...) as! T
let t = type whatever of c (so, maybe "A" or "B")
recycle[t].append( c )
let k = recycle[t].count
print wow, you have k of those already!
return c
}
Unfortunately, it's currently not possible for metatype types to conform to protocols (see this related question on the matter) – so CellThing.Type does not, and cannot, currently conform to Hashable. This therefore means that it cannot be used directly as the Key of a Dictionary.
However, you can create a wrapper for a metatype, using ObjectIdentifier in order to provide the Hashable implementation. For example:
/// Hashable wrapper for a metatype value.
struct HashableType<T> : Hashable {
static func == (lhs: HashableType, rhs: HashableType) -> Bool {
return lhs.base == rhs.base
}
let base: T.Type
init(_ base: T.Type) {
self.base = base
}
func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(base))
}
// Pre Swift 4.2:
// var hashValue: Int { return ObjectIdentifier(base).hashValue }
}
You can then also provide a convenience subscript on Dictionary that takes a metatype and wraps it in a HashableType for you:
extension Dictionary {
subscript<T>(key: T.Type) -> Value? where Key == HashableType<T> {
get { return self[HashableType(key)] }
set { self[HashableType(key)] = newValue }
}
}
which could then use like so:
class CellThing {}
class A : CellThing {}
class B : CellThing {}
var recycle: [HashableType<CellThing>: [CellThing]] = [:]
recycle[A.self] = [A(), A(), A()]
recycle[B.self] = [B(), B()]
print(recycle[A.self]!) // [A, A, A]
print(recycle[B.self]!) // [B, B]
This should also work fine for generics, you would simply subscript your dictionary with T.self instead.
Unfortunately one disadvantage of using a subscript with a get and set here is that you'll incur a performance hit when working with dictionary values that are copy-on-write types such as Array (such as in your example). I talk about this issue more in this Q&A.
A simple operation like:
recycle[A.self]?.append(A())
will trigger an O(N) copy of the array stored within the dictionary.
This is a problem that is aimed to be solved with generalised accessors, which have been implemented as an unofficial language feature in Swift 5. If you are comfortable using an unofficial language feature that could break in a future version (not really recommended for production code), then you could implement the subscript as:
extension Dictionary {
subscript<T>(key: T.Type) -> Value? where Key == HashableType<T> {
get { return self[HashableType(key)] }
_modify {
yield &self[HashableType(key)]
}
}
}
which solves the performance problem, allowing an array value to be mutated in-place within the dictionary.
Otherwise, a simple alternative is to not define a custom subscript, and instead just add a convenience computed property on your type to let you use it as a key:
class CellThing {
// Convenience static computed property to get the wrapped metatype value.
static var hashable: HashableType<CellThing> { return HashableType(self) }
}
class A : CellThing {}
class B : CellThing {}
var recycle: [HashableType<CellThing>: [CellThing]] = [:]
recycle[A.hashable] = [A(), A(), A()]
recycle[B.hashable] = [B(), B()]
print(recycle[A.hashable]!) // [A, A, A]
print(recycle[B.hashable]!) // [B, B]
If you extend the Dictionary type you can use the already defined generic Key directly.
extension Dictionary {
// Key and Value are already defined by type dictionary, so it's available here
func getSomething(key: Key) -> Value {
return self[key]
}
}
This works because Dictionary already has generics Key and Value defined for it's own use.
Hope AnyHashable helps. But It appeared in Xcode 8.0
You can do something like:
var info: [AnyHashable : Any]? = nil

Make a Swift dictionary where the key is "Type"?

I'm trying to do this sort of thing ..
static var recycle: [Type: [CellThing]] = []
but - I can't :)
Undeclared type 'Type'
In the example, CellThing is my base class, so A:CellThing, B:CellThing, C:CellThing and so on. The idea is I would store various A A A, B B, C C C C in the dictionary arrays.
How to make a "Type" (ideally I guess, constrained to CellThing) be the key in a Swift dictionary?
I appreciate I could (perhaps?) use String(describing: T.self), but that would make me lose sleep.
Here's a use case, envisaged code would look something like this ...
#discardableResult class func make(...)->Self {
return makeHelper(...)
}
private class func makeHelper<T: CellThing>(...)->T {
let c = instantiateViewController(...) as! T
return c
}
So then something like ...
static var recycle: [Type: [CellThing]] = []
private class func makeHelper<T: CellThing>(...)->T {
let c = instantiateViewController(...) as! T
let t = type whatever of c (so, maybe "A" or "B")
recycle[t].append( c )
let k = recycle[t].count
print wow, you have k of those already!
return c
}
Unfortunately, it's currently not possible for metatype types to conform to protocols (see this related question on the matter) – so CellThing.Type does not, and cannot, currently conform to Hashable. This therefore means that it cannot be used directly as the Key of a Dictionary.
However, you can create a wrapper for a metatype, using ObjectIdentifier in order to provide the Hashable implementation. For example:
/// Hashable wrapper for a metatype value.
struct HashableType<T> : Hashable {
static func == (lhs: HashableType, rhs: HashableType) -> Bool {
return lhs.base == rhs.base
}
let base: T.Type
init(_ base: T.Type) {
self.base = base
}
func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(base))
}
// Pre Swift 4.2:
// var hashValue: Int { return ObjectIdentifier(base).hashValue }
}
You can then also provide a convenience subscript on Dictionary that takes a metatype and wraps it in a HashableType for you:
extension Dictionary {
subscript<T>(key: T.Type) -> Value? where Key == HashableType<T> {
get { return self[HashableType(key)] }
set { self[HashableType(key)] = newValue }
}
}
which could then use like so:
class CellThing {}
class A : CellThing {}
class B : CellThing {}
var recycle: [HashableType<CellThing>: [CellThing]] = [:]
recycle[A.self] = [A(), A(), A()]
recycle[B.self] = [B(), B()]
print(recycle[A.self]!) // [A, A, A]
print(recycle[B.self]!) // [B, B]
This should also work fine for generics, you would simply subscript your dictionary with T.self instead.
Unfortunately one disadvantage of using a subscript with a get and set here is that you'll incur a performance hit when working with dictionary values that are copy-on-write types such as Array (such as in your example). I talk about this issue more in this Q&A.
A simple operation like:
recycle[A.self]?.append(A())
will trigger an O(N) copy of the array stored within the dictionary.
This is a problem that is aimed to be solved with generalised accessors, which have been implemented as an unofficial language feature in Swift 5. If you are comfortable using an unofficial language feature that could break in a future version (not really recommended for production code), then you could implement the subscript as:
extension Dictionary {
subscript<T>(key: T.Type) -> Value? where Key == HashableType<T> {
get { return self[HashableType(key)] }
_modify {
yield &self[HashableType(key)]
}
}
}
which solves the performance problem, allowing an array value to be mutated in-place within the dictionary.
Otherwise, a simple alternative is to not define a custom subscript, and instead just add a convenience computed property on your type to let you use it as a key:
class CellThing {
// Convenience static computed property to get the wrapped metatype value.
static var hashable: HashableType<CellThing> { return HashableType(self) }
}
class A : CellThing {}
class B : CellThing {}
var recycle: [HashableType<CellThing>: [CellThing]] = [:]
recycle[A.hashable] = [A(), A(), A()]
recycle[B.hashable] = [B(), B()]
print(recycle[A.hashable]!) // [A, A, A]
print(recycle[B.hashable]!) // [B, B]
If you extend the Dictionary type you can use the already defined generic Key directly.
extension Dictionary {
// Key and Value are already defined by type dictionary, so it's available here
func getSomething(key: Key) -> Value {
return self[key]
}
}
This works because Dictionary already has generics Key and Value defined for it's own use.
Hope AnyHashable helps. But It appeared in Xcode 8.0
You can do something like:
var info: [AnyHashable : Any]? = nil

Generic tail in Swift

tail for array:
private extension Array {
var tail: Array { get { return Array(dropFirst(self)) } }
}
And here is generic version for Sliceable:
public func tail<S: Sliceable>(sequence: S, initializer: ((S.SubSlice) -> S)) -> S {
return initializer(dropFirst(sequence))
}
let s = tail("12", {String($0)})
Is it possible to rewrite generic tail without initializer arg?
I.e. call initializer via sequence type (S() or something)?
For a sliceable type T, T.SubSlice can be different from T.
For example String.SubSlice == String, but Array.SubSlice == ArraySlice<T>.
You can define a protocol which describes all types which can be
created from their own subslices:
public protocol CreatableFromSubslice : Sliceable {
init(_ subslice : Self.SubSlice)
}
Even if most (all?) built-in sliceable types can be created from their own
subslice, you still have to tell that the compiler with empty
extensions:
extension String : CreatableFromSubslice { }
extension Array : CreatableFromSubslice { }
// ...
Then tail() can be defined as
public func tail<S: CreatableFromSubslice>(slice: S) -> S {
return S(dropFirst(slice))
}
Example:
let s = tail("12")
println(s) // "2"
let a = tail([1, 2, 3])
println(a) // [2, 3]
For types which are equal to their subslice type you could define
public func tail<S: Sliceable where S.SubSlice == S >(slice: S) -> S {
return dropFirst(slice)
}
This can be applied to String, but not to Array.

Can I extend Tuples in Swift?

I'd like to write an extension for tuples of (e.g.) two value in Swift. For instance, I'd like to write this swap method:
let t = (1, "one")
let s = t.swap
such that s would be of type (String, Int) with value ("one", 1). (I know I can very easily implement a swap(t) function instead, but that's not what I'm interested in.)
Can I do this? I cannot seem to write the proper type name in the extension declaration.
Additionally, and I suppose the answer is the same, can I make a 2-tuple adopt a given protocol?
You cannot extend tuple types in Swift.
According to
Types, there are named types (which
can be extended) and compound types. Tuples and functions are compound
types.
See also (emphasis added):
Extensions
Extensions add new functionality to an existing
class, structure, or enumeration type.
As the answer above states, you cannot extend tuples in Swift. However, rather than just give you a no, what you can do is box the tuple inside a class, struct or enum and extend that.
struct TupleStruct {
var value: (Int, Int)
}
extension TupleStruct : Hashable {
var hashValue: Int {
return hash()
}
func hash() -> Int {
var hash = 23
hash = hash &* 31 &+ value.0
return hash &* 31 &+ value.1
}
}
func ==(lhs: TupleStruct, rhs: TupleStruct) -> Bool {
return lhs.value == rhs.value
}
As a side note, in Swift 2.2, tuples with up to 6 members are now Equatable.
Details
Xcode 11.2.1 (11B500), Swift 5.1
Solution
struct Tuple<T> {
let original: T
private let array: [Mirror.Child]
init(_ value: T) {
self.original = value
array = Array(Mirror(reflecting: original).children)
}
func getAllValues() -> [Any] { array.compactMap { $0.value } }
func swap() -> (Any?, Any?)? {
if array.count == 2 { return (array[1].value, array[0].value) }
return nil
}
}
Usage
let x = (1, "one")
let tuple = Tuple(x)
print(x) // (1, "one")
print(tuple.swap()) // Optional((Optional("one"), Optional(1)))
if let value = tuple.swap() as? (String, Int) {
print("\(value) | \(type(of: value))") // ("one", 1) | (String, Int)
}
If you wanted to be a Bad Person™ you can define custom operators on tuples, like this:
postfix operator <->
postfix func <-> <A, B>(lhs: (A, B)) -> (B, A) {
return (lhs.1, lhs.0)
}
let initial = (1, "one")
let reversed = initial<->
FWIW I can't think of a place where my 'clever' code trumps the readability of just writing your swap function.