having difficulties understanding complex swift associatedtype declaration - swift

I saw the line of code below at swift github repository
associatedtype Indices : _RandomAccessIndexable, BidirectionalCollection
= DefaultRandomAccessIndices<Self>
I know that an associatedtype is an type alias for protocols, and i know how to interpret it in simple cases
But can someone please explain to me the line of code i saw from swift github repository?

That means that the associated type Indices must conform to
_RandomAccessIndexable and BidirectionalCollection, and by default is DefaultRandomAccessIndices<Self> unless declared (or inferred) otherwise (where Self is the actual type adopting the protocol).
Example:
struct MyIndex : Comparable {
var value : Int16
static func ==(lhs : MyIndex, rhs : MyIndex) -> Bool {
return lhs.value == rhs.value
}
static func <(lhs : MyIndex, rhs : MyIndex) -> Bool {
return lhs.value < rhs.value
}
}
struct MyCollectionType : RandomAccessCollection {
var startIndex : MyIndex { return MyIndex(value: 0) }
var endIndex : MyIndex { return MyIndex(value: 3) }
subscript(position : MyIndex) -> String {
return "I am element #\(position.value)"
}
func index(after i: MyIndex) -> MyIndex {
guard i != endIndex else { fatalError("Cannot increment endIndex") }
return MyIndex(value: i.value + 1)
}
func index(before i: MyIndex) -> MyIndex {
guard i != startIndex else { fatalError("Cannot decrement startIndex") }
return MyIndex(value: i.value - 1)
}
}
let coll = MyCollectionType()
let i = coll.indices
print(type(of: i)) // DefaultRandomAccessIndices<MyCollectionType>
MyCollectionType is a (minimal?) implementation of a
RandomAccessCollection, using a custom index type MyIndex.
It does not define its own indices method or Indices type,
so that Indices becomes the default associated type,
and
indices
is a default protocol extension method of RandomAccessCollection.

Related

How to get next case of enum(i.e. write a circulating method) in Swift 4.2

Swift 4.2 introduces a new CaseIterable protocol that automatically generates an array property of all cases in an enum.
Now I want to implement a default method for Enum inherits from CaseIterable that can return the next case of a giving case. If this case is the last case, return the first case. Like a circle.
If I write this for specific Enum, it works correctly:
enum Direction: CaseIterable {
case east, south, west, north
func next() -> Direction {
let all = type(of: self).allCases // 1
if self == all.last! {
return all.first!
} else {
let index = all.firstIndex(of: self)!
return all[index + 1]
}
}
}
print(Direction.east.next()) // south
print(Direction.north.next()) // east
But I want to implement this function to many Enum. Copying and pasting code repeatedly are not good (Not to mention this code is totally the same for every Enum).
So I tried this. But something went wrong.
(I suggest you copy following code to playground that you can understand this problem more quickly):
extension CaseIterable {
func next() -> Self {
let all = type(of: self).allCases // 1
if self == all.last { // 2
return all.first!
} else {
let index = all.firstIndex { (ele) -> Bool in
self == ele // 3
}
return all[index + 1]
}
}
}
Three points:
all's type is Self.AllCases, which is a Collection type. But in the method above, it's [Direction].
There's an error at line 2 says Value of type 'Self.AllCases' has no member 'last'
(Even I avoid to use last, the error at line 3 can't be avoided.)
At line 3, the error is Binary operator '==' cannot be applied to two 'Self' operands
And even I use generic constraints, it's the same.
func next<T: CaseIterable>(element: T) -> T {...}
Any solutions? :)
Some problems with your approach are:
The Collection protocol does not define a last property.
In order to compare the elements with == they have to be Equatable.
Collection indices are not necessarily integers, they must be incremented
with index(after:).
This seems to be a working solution (tested with Xcode 10.0 beta 2):
extension CaseIterable where Self: Equatable {
func next() -> Self {
let all = Self.allCases
let idx = all.firstIndex(of: self)!
let next = all.index(after: idx)
return all[next == all.endIndex ? all.startIndex : next]
}
}
Example:
enum Direction: CaseIterable {
case east, south, west, north
}
print(Direction.east.next()) // south
print(Direction.north.next()) // east
Remarks:
Only enumerations without associated values are CaseIterable, and
those are also Equatable (but the compiler does not figure out that
by itself). Therefore Self: Equatable is not a
real restriction.
Self.allCases can be used in Swift 4.2 to access the type property
from an instance method.
The forced unwrapping is safe because we know that the value is
an element of allCases.
Your enum Direction: CaseIterable compiles because the concrete
enum Direction type is Equatable, and its Direction.allCases is an Array – which has integer indices and a last property.
If someone is interested into both previous and next cases, here's an upgrade of the previous answer:
extension CaseIterable where Self: Equatable, AllCases: BidirectionalCollection {
func previous() -> Self {
let all = Self.allCases
let idx = all.index(of: self)!
let previous = all.index(before: idx)
return all[previous < all.startIndex ? all.index(before: all.endIndex) : previous]
}
func next() -> Self {
let all = Self.allCases
let idx = all.index(of: self)!
let next = all.index(after: idx)
return all[next == all.endIndex ? all.startIndex : next]
}
}
Actually you don't need BidirectionalCollection conformance to implement previous case as well.
extension CaseIterable where Self: Equatable {
func previous() -> Self {
let all = Self.allCases
var idx = all.firstIndex(of: self)!
if idx == all.startIndex {
let lastIndex = all.index(all.endIndex, offsetBy: -1)
return all[lastIndex]
} else {
all.formIndex(&idx, offsetBy: -1)
return all[idx]
}
}
func next() -> Self {
let all = Self.allCases
let idx = all.firstIndex(of: self)!
let next = all.index(after: idx)
return all[next == all.endIndex ? all.startIndex : next]
}
}
You can also make a more generic cyclic offset function:
extension CaseIterable where Self: Equatable {
func advanced(by n: Int) -> Self {
let all = Array(Self.allCases)
let idx = (all.firstIndex(of: self)! + n) % all.count
print(idx)
if idx >= 0 {
return all[idx]
} else {
return all[all.count + idx]
}
}
}
2022
We can create extension:
extension Collection {
subscript (infinityIdx idx: Index) -> Element where Index == Int {
return self[ idx % self.count ]
}
}
lets try this ext in action:
enum SomeEnum: CaseIterable {
case v1, v2, v3, v4
}
for i in 0...15 {
print(SomeEnum.allCases[infinityIdx: i] )
}
result:
v1
v2
v3
v4
v1
v2
v3
v4
v1
v2
v3

Trying to get generic code from working Iterator pattern

Here is the code that works fine and this is implementation of the Iterator pattern:
struct Candies {
let candies: [String]
}
extension Candies: Sequence {
func makeIterator() -> CandiesIterator {
return CandiesIterator(sequence: candies, current: 0)
}
}
struct CandiesIterator: IteratorProtocol {
let sequence: [String]
var current = 0
mutating func next() -> String? {
defer { current += 1 }
return sequence.count > current ? sequence[current] : nil
}
}
Here is the code that I thought to be as a generic variation of the code above but I have two errors (see below the code):
struct Whatevers<T> {
let whatevers: [T]
}
extension Whatevers: Sequence {
func makeIterator() -> Whatevers<T>.Iterator {
return WhateversIterator(sequence: whatevers, current: 0)
}
}
struct WhateversIterator<T>: IteratorProtocol {
let sequence: [T]
var current = 0
mutating func next() -> WhateversIterator.Element? {
defer { current += 1 }
return sequence.count > current ? sequence[current] : nil
}
}
error: MyPlayground.playground:854:1: error: type 'Whatevers' does
not conform to protocol 'Sequence' extension Whatevers: Sequence { ^
error: MyPlayground.playground:861:8: error: type
'WhateversIterator' does not conform to protocol 'IteratorProtocol'
struct WhateversIterator: IteratorProtocol {
Can someone explain what is incorrect in this code. And how can I make it work?
Solution found!
struct Whatevers<T> {
let whatevers: [T]
}
extension Whatevers: Sequence {
func makeIterator() -> WhateversIterator<T> {
return WhateversIterator(sequence: whatevers, current: 0)
}
}
struct WhateversIterator<T>: IteratorProtocol {
let sequence: [T]
var current = 0
mutating func next() -> T? {
defer { current += 1 }
return sequence.count > current ? sequence[current] : nil
}
}
All the mistakes were about returning types from functions makeIterator and next.
Hope somebody will find it helpful!

Getting a random element in array by a generic function

func ramElment<X, T: CollectionType >(list: T) -> X {
let len = UInt32(list.count)
let element = arc4random_uniform(len)
return list[element]
}
it pops up:
error: cannot invoke initializer for type UInt32 with an argument list of type '(T.Index.Distance)'
let len = UInt32(list.count)
I have checked the T.Index.Distance is Int type. but why can't i change the type to UInt32?
thanks!
The Index of a CollectionType is
a ForwardIndexType:
public protocol ForwardIndexType : _Incrementable {
// ...
typealias Distance : _SignedIntegerType = Int
// ...
}
This means that the associated type Distance must conform to _SignedIntegerType, and (by default) is Int unless declared (or inferred)
otherwise.
Example: The following is a valid type conforming to ForwardIndexType,
with Distance == Int16:
struct MyIndex : ForwardIndexType {
var value : Int16
func advancedBy(n: Int16) -> MyIndex {
return MyIndex(value: value + n)
}
func distanceTo(end: MyIndex) -> Int16 {
return end.value - value
}
func successor() -> MyIndex {
return MyIndex(value: value + 1)
}
}
func ==(lhs : MyIndex, rhs : MyIndex) -> Bool {
return lhs.value == rhs.value
}
And here is a (for demonstration purposes, otherwise pretty useless)
type conforming to CollectionType with Index == MyIndex,
Index.Distance == Int16:
struct MyCollectionType : CollectionType {
var startIndex : MyIndex { return MyIndex(value: 0) }
var endIndex : MyIndex { return MyIndex(value: 3) }
subscript(position : MyIndex) -> String {
return "I am element #\(position.value)"
}
}
Example:
let coll = MyCollectionType()
for elem in coll {
print(elem)
}
/*
I am element #0
I am element #1
I am element #2
*/
But we can also define a forward index type without declaring
any Distance type, and using the default protocol implementations
for advancedBy() and distanceTo():
struct MyOtherIndex : ForwardIndexType {
var value : Int16
func successor() -> MyOtherIndex {
return MyOtherIndex(value: value + 1)
}
}
func ==(lhs : MyOtherIndex, rhs : MyOtherIndex) -> Bool {
return lhs.value == rhs.value
}
Now MyOtherIndex.Distance == Int because that is the default type
as defined in ForwardIndexType.
So how does this apply to your function?
You cannot assume that
Index.Distance is Int for an arbitrary collection.
You can restrict the function to collection types with
Index.Distance == Int:
func randomElement<T: CollectionType where T.Index.Distance == Int>(list: T)
But you can also utilize that _SignedIntegerType can be converted to and from IntMax:
func randomElement<T: CollectionType>(list: T) -> T.Generator.Element {
let len = UInt32(list.count.toIntMax())
let element = IntMax(arc4random_uniform(len))
return list[list.startIndex.advancedBy(T.Index.Distance(element))]
}
Note also that the return type is determined as T.Generator.Element,
and cannot be an arbitrary generic type X.
This function works with arbitrary collections, for example Array, ArraySlice, or String.CharacterView:
let array = [1, 1, 2, 3, 5, 8, 13]
let elem1 = randomElement([1, 2, 3])
let slice = array[2 ... 3]
let elem2 = randomElement(slice)
let randomChar = randomElement("abc".characters)
but also with the above custom collection type:
let mc = MyCollectionType()
let r = randomElement(mc)
In the title of your question you talk about Array. But in your code you are declaring the input param as a CollectionType.
If you really want to receive a Generic Array param then this is the code
func randomElement<T>(list: [T]) -> T {
let len = UInt32(list.count)
let random = Int(arc4random_uniform(len))
return list[random]
}
This is the simplest example what you want.
extension CollectionType where Index.Distance == Int {
func randomElement() -> Self.Generator.Element {
let randomIndex = Int(arc4random_uniform(UInt32(count)))
return self[startIndex.advancedBy(randomIndex)]
}
}

How can I write a function that will unwrap a generic property in swift assuming it is an optional type?

So far I have only been able to achieve this using a global function. I am not sure if it is possible but I was hoping to write an extension to a generic class that would hopefully achieve the same thing.
Below is the working global function it is using SignalProducer class from ReactiveCocoa but the principle should be the same for any generic class.
func ignoreNilValues <Value,Error> (producer: SignalProducer<Value?,Error>) -> SignalProducer<Value, Error> {
return producer.filter { return $0 != nil }.map { $0! }
}
Update:
I have made progress but have still fallen short of a complete solution
Given any class with some generic property
class GenericClass<SomeType> {
var someProperty: [SomeType] = []
}
How can I write an extension that will filter any optional values and return the value using the Wrapped type?
The following will filter any nil values but still return it as the Optional type.
protocol AnOptional {
var isNil: Bool {get}
}
extension Optional : AnOptional {
var isNil: Bool {
get {
guard let hasValue = self.map({ (value: Wrapped) -> Bool in
return true
}) else {
return true
}
return !hasValue
}
}
}
extension GenericClass where SomeType : AnOptional {
func filterNilValuesOfSomeProperty() -> [SomeType] {
return someProperty.filter({ (anOptional: AnOptional) -> Bool in
return !anOptional.isNil
})
}
}
As can be seen
let aClass = GenericClass<Int?>()
aClass.someProperty = [3,5,6,nil,4,3,6, nil]
let x = aClass.someProperty
//x = [Some(3),Some(5),Some(6),nil,Some(4),Some(3),Some(6), nil]
let y = aClass.filterNilValuesOfSomeProperty()
//y = [Some(3),Some(5),Some(6),Some(4),Some(3),Some(6)]
Is it possible to write a class extension that would return the wrapped type? In the example above it would be [Int] instead of [Int?].
I rewrote the global function solution for this example.
func ignoreNilValues <Value> (aClass: GenericClass<Value?>) -> GenericClass<Value> {
let aNewClass = GenericClass<Value>()
aNewClass.someProperty = aClass.someProperty.filter({ (v: Value?) -> Bool in
v != nil
}).map { (oldValue: Value?) -> Value in
return oldValue!
}
return aNewClass
}
let z = ignoreNilValues(aClass).someProperty
//z = [3, 5, 6, 4, 3, 6]
The "trick" is to define a protocol to which all optionals conform
(this is from Creating an extension to filter nils from an Array in Swift
with a minor simplification; the idea goes back to this Apple Forum Thread):
protocol OptionalType {
typealias Wrapped
func intoOptional() -> Wrapped?
}
extension Optional : OptionalType {
func intoOptional() -> Wrapped? {
return self
}
}
You can use that in your case as:
class GenericClass<SomeType> {
var someProperty: [SomeType] = []
}
extension GenericClass where SomeType : OptionalType {
func filterNilValuesOfSomeProperty() -> [SomeType.Wrapped] {
return someProperty.flatMap { $0.intoOptional() }
}
}
which uses the flatMap() method from SequenceType:
extension SequenceType {
/// Return an `Array` containing the non-nil results of mapping
/// `transform` over `self`.
///
/// - Complexity: O(*M* + *N*), where *M* is the length of `self`
/// and *N* is the length of the result.
#warn_unused_result
public func flatMap<T>(#noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T]
}
Example:
let aClass = GenericClass<Int?>()
aClass.someProperty = [3,5,6,nil,4,3,6, nil]
let x = aClass.someProperty
print(x) // [Optional(3), Optional(5), Optional(6), nil, Optional(4), Optional(3), Optional(6), nil]
let y = aClass.filterNilValuesOfSomeProperty()
print(y) // [3, 5, 6, 4, 3, 6]
In Swift 3 and later the protocol has to be defined as
protocol OptionalType {
associatedtype Wrapped
func intoOptional() -> Wrapped?
}
I have this solution using in my app, create a protocol, and added an extension to Optional.
protocol OptionalUnwrap {
associatedtype Wrapped
func unwrap(default defaultValue: #autoclosure () -> Wrapped) -> Wrapped
}
extension Optional: OptionalUnwrap {
func unwrap(default defaultValue: #autoclosure () -> Wrapped) -> Wrapped {
if let value = self {
return value
}
return defaultValue()
}
}
You can use it like this, you have to provide a default value, so if optional is nil it will return the default value. It works with all types.
struct StructName {
var name: String
var age: Int
}
var structName3: StructName?
let unwrapped = structName3.unwrap(default: StructName(name: "", age: 2345))
print(unwrapped.age)
var version: Int?
version.unwrap(default: 5)
var subject: String? = "iOS"
subject.unwrap(default: "")

Comparing objects in an Array extension causing error in Swift

I'm trying to build an extension that adds some of the convenience functionality of NSArray/NSMutableArray to the Swift Array class, and I'm trying to add this function:
func indexOfObject(object:AnyObject) -> Int? {
if self.count > 0 {
for (idx, objectToCompare) in enumerate(self) {
if object == objectToCompare {
return idx
}
}
}
return nil
}
But unfortunately, this line:
if object == objectToCompare {
Is giving the error:
could not find an overload for '==' that accepts the supplied arguments
Question
What am I doing wrong to cause this error?
Example
extension Array {
func indexOfObject(object:AnyObject) -> Int? {
if self.count > 0 {
for (idx, objectToCompare) in enumerate(self) {
if object == objectToCompare {
return idx
}
}
}
return nil
}
}
Actually there is no need to implement indexOfObject:; there is a global function find(array, element) already.
You can always create an extension that uses NSArray's indexOfObject, e.g:
extension Array {
func indexOfObject(object:AnyObject) -> Int? {
return (self as NSArray).indexOfObject(object)
}
}
You can specify that your array items can be compared with the <T : Equatable> constraint, then you can cast your object into T and compare them, e.g:
extension Array {
func indexOfObject<T : Equatable>(o:T) -> Int? {
if self.count > 0 {
for (idx, objectToCompare) in enumerate(self) {
let to = objectToCompare as T
if o == to {
return idx
}
}
}
return nil
}
}
My guess is that you have to do something like this:
func indexOfObject<T: Equatable>(object: T) -> Int? {
and so on.
Here's a relevant example from Apple's "The Swift Programming Language" in the "Generics" section:
func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
The key idea here is that both value and valueToFind must of a type that is guaranteed to have the == operator implemented/overloaded. The <T: Equatable> is a generic that allows only objects of a type that are, well, equatable.
In your case, we would need to ensure that the array itself is composed only of objects that are equatable. The Array is declared as a struct with a generic <T> that does not require it to be equatable, however. I don't know whether it is possible to use extensions to change what kind of types an array can be composed of. I've tried some variations on the syntax and haven't found a way.
You can extract the compare part to another helper function, for example
extension Array {
func indexOfObject(object: T, equal: (T, T) -> Bool) -> Int? {
if self.count > 0 {
for (idx, objectToCompare) in enumerate(self) {
if equal(object, objectToCompare) {
return idx
}
}
}
return nil
}
}
let arr = [1, 2, 3]
arr.indexOfObject(3, ==) // which returns {Some 2}
You were close. Here's a working extension:
extension Array {
func indexOfObject<T: Equatable>(object:T) -> Int? {
if self.count > 0 {
for (idx, objectToCompare) in enumerate(self) {
if object == objectToCompare as T {
return idx
}
}
}
return nil
}
}
Swift had no way of knowing if object or objectToCompare were equatable. By adding generic information to the method, we're then in business.