conforming to Sequence and IteratorProtocol in Swift - swift

I am trying to write my own version of IndexingIterator to increase my understanding of Sequence. I haven't assign any type to associatetype Iterator in my struct. However, the complier doesn't complain about that and I get a default implementation of makeIterator.
Following are my codes:
struct __IndexingIterator<Elements: IndexableBase>: Sequence, IteratorProtocol {
mutating func next() -> Elements._Element? {
return nil
}
}
let iterator = __IndexingIterator<[String]>()
// this works and returns an instance of __IndexingIterator<Array<String>>. why?
iterator.makeIterator()
I think there must be some extensions on Sequence which add the default implementation. Thus, I searched it in Sequence.swift and only found this.
extension Sequence where Self.Iterator == Self, Self : IteratorProtocol {
/// Returns an iterator over the elements of this sequence.
public func makeIterator() -> Self {
return self
}
}
I thought it would be like this:
extension Sequence where Self: IteratorProtocol {
typealias Iterator = Self
...
}
Did I miss something or I misunderstood the extension?

It looks like Alexander's answer is correct. Here's a boiled down version, without using Sequence:
protocol MySequence {
associatedtype Iterator: IteratorProtocol
func maakeIterator() -> Iterator
}
extension MySequence where Self.Iterator == Self, Self : IteratorProtocol {
/// Returns an iterator over the elements of this sequence.
func maakeIterator() -> Self {
return self
}
}
struct __IndexingIterator<Element>: MySequence, IteratorProtocol {
mutating func next() -> Element? {
return nil
}
}
let iterator = __IndexingIterator<[String]>()
iterator.maakeIterator()

You can write your own Iterator which confrom to IteratorProtocol first, then write what you need confrom to Sequence.
Make sure that you have to implement requried func.
struct IteratorTest : IteratorProtocol {
typealias Element = Int
var count : Int
init(count :Int) {
self.count = count
}
mutating func next() -> Int? {
if count == 0 {
return nil
}else {
defer {
count -= 1
}
return count;
}
}
}
struct CountDown : Sequence {
typealias Iterator = IteratorTest
func makeIterator() -> IteratorTest {
return IteratorTest.init(count: 10)
}
}

The type alias isn't necessary, because the Element associated type is inferred from your implementation of next().
Here's a simple example:
protocol ResourceProvider {
associatedtype Resoruce
func provide() -> Resoruce;
}
struct StringProvider {
func provide() -> String { // "Resource" inferred to be "String"
return "A string"
}
}

Related

how to store away sequence variables with constraints in swift

I wanted to create a "where_non_null" operation that works on any swift sequence - which is easy if you return an array, but obviously that is potentially bad performance wise - because you are forcing the entire sequence to resolve in memory - so I created the following that just goes line by line:
//
// this iterates through the underlying sequence, and returns only the values that are not null
//
public class Not_null_iterator<T> : IteratorProtocol
{
public typealias Element = T
private let next_function : () -> T?
init<T_iterator: IteratorProtocol>( _ source: T_iterator ) where T_iterator.Element == Optional<T>
{
var iterator = source
next_function =
{
while (true)
{
if let next_value = iterator.next()
{
if let not_null_value = next_value
{
return not_null_value
}
}
else
{
return nil
}
}
}
}
public func next() -> T? {
next_function()
}
}
//
// a sequence wrapping an underlying sequence, that removes any nulls as we go through
//
public class Not_null_sequence<T > : Sequence
{
private var iterator_creator : () -> Not_null_iterator<T>
init<T_source_sequence : Sequence >( _ source : T_source_sequence ) where T_source_sequence.Element == Optional<T>
{
iterator_creator =
{
Not_null_iterator(source.makeIterator())
}
}
public func makeIterator() -> Not_null_iterator<T>
{
iterator_creator()
}
}
extension Sequence
{
//
// return only the not null values in the sequence without ever resolving more than one item in memory at one time and remove the optionality on the type
//
func where_not_null<T>() -> Not_null_sequence<T> where Element == Optional<T>
{
return Not_null_sequence( self)
}
}
class Where_not_null_tests : XCTestCase
{
public func test_where_not_null()
{
let source = [1, 2, 3, nil, 4]
let checked : [Int] = Array(source.where_not_null())
XCTAssertEqual([1,2,3,4],checked)
}
}
which works great - however I had to define the next() and make_iterator() functions in the constructor, because I couldn't find any type safe way of putting the source into a class level variable.
Is there a way of doing that?
[and yes, I'm aware swift people prefer camel case]
Rather than just using one generic parameter, you'd need two generic parameters. You can't just constrain one generic parameter to say that it has to be some sequence with an element of some Optional. You need another generic parameter to say what the optional's type is:
class NotNilIterator<T: IteratorProtocol, U>: IteratorProtocol where T.Element == U? {
typealias Element = U
var iterator: T
init(_ source: T) {
iterator = source
}
func next() -> Element? {
// I feel this is clearer what is going on
while true {
switch iterator.next() {
case .some(.none):
continue
case .none:
return nil
case .some(.some(let element)):
return element
}
}
}
}
class NotNilSequence<T: Sequence, U> : Sequence where T.Element == U?
{
let sequence: T
init(_ source : T)
{
sequence = source
}
public func makeIterator() -> NotNilIterator<T.Iterator, U>
{
.init(sequence.makeIterator())
}
}
whereNotNil would then be declared like this:
func whereNotNil<T>() -> NotNilSequence<Self, T> where Self.Element == T?
{
return .init(self)
}
Note the use of self types. The first parameter is the type of the underlying sequence, the second is the non-optional type.
Note that this sort of "lazily computed sequence" is already built into Swift. To lazily filter out the nils, do:
let array = [1, 2, 3, nil, 4]
let arrayWithoutNil = array.lazy.compactMap { $0 }
The downside is that the type names are quite long. arrayWithoutNil is of type
LazyMapSequence<LazyFilterSequence<LazyMapSequence<LazySequence<[Int?]>.Elements, Int?>>, Int>
But you can indeed get non-optional Ints out of it, so it does work.
The way swift generics work can sometimes be very confusing (but has it's advantages). Instead of declaring that a variable is of a generic protocol (resp. a protocol with associated types), you instead declare another generic type which itself conforms to your protocol. Here's your iterator as an example (I have taken the liberty to clean up the code a bit):
public class Not_null_iterator<T, T_iterator> : IteratorProtocol where
T_iterator: IteratorProtocol,
T_iterator.Element == Optional<T>
{
private var source: T_iterator
init(_ source: T_iterator) {
self.source = source
}
public func next() -> T? {
while let next_value = source.next()
{
if let not_null_value = next_value
{
return not_null_value
}
}
return nil
}
}
The non-null sequence works analogous:
public class Not_null_sequence<T, Source>: Sequence where
Source: Sequence,
Source.Element == Optional<T>
{
private var source: Source
init(_ source: Source) {
self.source = source
}
public func makeIterator() -> Not_null_iterator<T, Source.Iterator> {
Not_null_iterator(self.source.makeIterator())
}
}
Using this some IteratorProtocol is just a nice way to let the compiler figure out the type. It is equivalent to saying Not_null_iterator<T, Source.Iterator>
As a (potentially) interesting side-note, to clean up the generic mess even more, you can nest the iterator class inside the Not_null_sequence:
public class Not_null_sequence<T, Source>: Sequence where
Source: Sequence,
Source.Element == Optional<T>
{
private var source: Source
init(_ source: Source) {
self.source = source
}
public func makeIterator() -> Iterator{
Iterator(self.source.makeIterator())
}
public class Iterator: IteratorProtocol {
private var source: Source.Iterator
init(_ source: Source.Iterator) {
self.source = source
}
public func next() -> T? {
while let next_value = source.next()
{
if let not_null_value = next_value
{
return not_null_value
}
}
return nil
}
}
}

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!

Adopting CollectionType (Collection) in Swift

I'm writing a graphics library to display data in a graph. Since most of the projects I do tend to have a large learning component in them, I decided to create a generically typed struct to manage my data set DataSet<T: Plottable> (note here that Plottable is also Comparable).
In trying to conform to MutableCollectionType, I've run across an error. I'd like to use the default implementation of sort(), but the compiler is giving the following error when trying to use the sorting function.
Ambiguous reference to member 'sort()'
Here's a code example:
var data = DataSet<Int>(elements: [1,2,3,4])
data.sort() //Ambiguous reference to member 'sort()'
The compiler suggests two candidates, but will not actually display them to me. Note that the compiler error goes away if I explicitly implement sort() on my struct.
But the bigger question remains for me. What am I not seeing that I expect the default implementation to be providing? Or am I running across a bug in Swift 3 (this rarely is the case... usually I have overlooked something).
Here's the balance of the struct:
struct DataSet<T: Plottable>: MutableCollection, BidirectionalCollection {
typealias Element = T
typealias Iterator = DataSetIterator<T>
typealias Index = Int
/**
The list of elements in the data set. Private.
*/
private var elements: [Element] = []
/**
Initalize the data set with an array of data.
*/
init(elements data: [T] = []) {
self.elements = data
}
//MARK: Sequence Protocol
func makeIterator() -> DataSetIterator<T> {
return DataSetIterator(self)
}
//MARK: Collection Protocol
subscript(_ index:DataSet<T>.Index) -> DataSet<T>.Iterator.Element {
set {
elements[index] = newValue
}
get {
return elements[index]
}
}
subscript(_ inRange:Range<DataSet<T>.Index>) -> DataSet<T> {
set {
elements.replaceSubrange(inRange, with: newValue)
}
get {
return DataSet<T>(elements: Array(elements[inRange]))
}
}
//required index for MutableCollection and BidirectionalCollection
var endIndex: Int {
return elements.count
}
var startIndex: Int {
return 0
}
func index(after i: Int) -> Int {
return i+1
}
func index(before i: Int) -> Int {
return i-1
}
mutating func append(_ newElement: T) {
elements.append(newElement)
}
// /**
// Sorts the elements of the DataSet from lowest value to highest value.
// Commented because I'd like to use the default implementation.
// - note: This is equivalent to calling `sort(by: { $0 < $1 })`
// */
// mutating func sort() {
// self.sort(by: { $0 < $1 })
// }
//
// /**
// Sorts the elements of the DataSet by an abritrary block.
// */
// mutating func sort(by areInIncreasingOrder: #noescape (T, T) -> Bool) {
// self.elements = self.elements.sorted(by: areInIncreasingOrder)
// }
/**
Returns a `DataSet<T>` with the elements sorted by a provided block.
This is the default implementation `sort()` modified to return `DataSet<T>` rather than `Array<T>`.
- returns: A sorted `DataSet<T>` by the provided block.
*/
func sorted(by areInIncreasingOrder: #noescape (T, T) -> Bool) -> DataSet<T> {
return DataSet<T>(elements: self.elements.sorted(by: areInIncreasingOrder))
}
func sorted() -> DataSet<T> {
return self.sorted(by: { $0 < $1 })
}
}
Your DataSet is a BidirectionalCollection. The sort() you're trying to use requires a RandomAccessCollection. The most important thing you need to add is an Indicies typealias.
typealias Indices = Array<Element>.Indices
Here's my version of your type:
protocol Plottable: Comparable {}
extension Int: Plottable {}
struct DataSet<Element: Plottable>: MutableCollection, RandomAccessCollection {
private var elements: [Element] = []
typealias Indices = Array<Element>.Indices
init(elements data: [Element] = []) {
self.elements = data
}
var startIndex: Int {
return elements.startIndex
}
var endIndex: Int {
return elements.endIndex
}
func index(after i: Int) -> Int {
return elements.index(after: i)
}
func index(before i: Int) -> Int {
return elements.index(before: i)
}
subscript(position: Int) -> Element {
get {
return elements[position]
}
set {
elements[position] = newValue
}
}
subscript(bounds: Range<Int>) -> DataSet<Element> {
get {
return DataSet(elements: Array(elements[bounds]))
}
set {
elements[bounds] = ArraySlice(newValue.elements)
}
}
}
var data = DataSet(elements: [4,2,3,1])
data.sort()
print(data.elements) // [1,2,3,4]
You don't actually need an Iterator if you don't want one. Swift will give you Sequence automatically if you implement Collection.

RxSwift unwrap optional handy function?

Currently I have created a function unwrapOptional to safely unwrap the optional input in the stream.
func unwrapOptional<T>(x: Optional<T>) -> Observable<T> {
return x.map(Observable.just) ?? Observable.empty()
}
let aOpt: String? = "aOpt"
_ = Observable.of(aOpt).flatMap(unwrapOptional).subscribeNext { x in print(x)}
let aNil: String? = nil
_ = Observable.of(aNil).flatMap(unwrapOptional).subscribeNext { x in print(x)}
let a: String = "a"
_ = Observable.of(a).flatMap(unwrapOptional).subscribeNext { x in print(x)}
// output
aOpt
a
What I want to archive is to create a handy function instead of using flatMap(unwrapOptional), for example
Observable.of(a).unwrapOptional()
Something I tried to do, but it never compiles...
extension ObservableType {
func unwrapOptional<O : ObservableConvertibleType>() -> RxSwift.Observable<O.E> {
return self.flatMap(unwrapOptional)
}
}
You want the unwrapOptional method to only work on observables that have optional type.
So you somehow have to constraint the Element of Observable to conform to the Optional protocol.
extension Observable where Element: OptionalType {
/// Returns an Observable where the nil values from the original Observable are
/// skipped
func unwrappedOptional() -> Observable<Element.Wrapped> {
return self.filter { $0.asOptional != nil }.map { $0.asOptional! }
}
}
Unfortunately, Swift does not define such a protocol (OptionalType). So you also need to define it yourself
/// Represent an optional value
///
/// This is needed to restrict our Observable extension to Observable that generate
/// .Next events with Optional payload
protocol OptionalType {
associatedtype Wrapped
var asOptional: Wrapped? { get }
}
/// Implementation of the OptionalType protocol by the Optional type
extension Optional: OptionalType {
var asOptional: Wrapped? { return self }
}
checkout unwrap at https://github.com/RxSwiftCommunity/RxSwift-Ext :)
or https://github.com/RxSwiftCommunity/RxOptional
For now, you should use RxOptional for your personal needs
However, RxSwift-Ext will be growth exponentially in next 2-3 months :)
RxSwift now supports compactMap(). So, now you can do things like:
func unwrap(_ a: Observable<Int?>) -> Observable<Int> {
return a.compactMap { $0 }
}
Here's a version without needing OptionalType (from https://stackoverflow.com/a/36788483/13000)
extension Observable {
/// Returns an `Observable` where the nil values from the original `Observable` are skipped
func unwrap<T>() -> Observable<T> where Element == T? {
self
.filter { $0 != nil }
.map { $0! }
}
}

Specify relationships between protocols in Swift

I want to specify a protocol that manages some type objects that conform to another protocol. Like this:
// Specify protocol
protocol ElementGenerator {
func getElements() -> [Element]
}
protocol Element {
// ...
}
// Implement
class FooElementGenerator: ElementGenerator {
func getElements() -> [FooElement] {
// Generate elements here
return [FooElement()]
}
}
class FooElement {
// ...
}
When trying to compile this, I get an error:
Type 'FooElementGenerator' does not conform to protocol 'ElementGenerator'
hinting that candidate func getElements() -> [FooElement] has non-matching type of () -> [FooElement], but instead it expects () -> [Element].
How this kind of an error can be fixed?
UPDATE:
This solution seems to be working:
protocol ElementGenerator {
typealias T:Element
func getElements() -> [T]
}
protocol Element {
// ...
}
class FooElementGenerator: ElementGenerator {
typealias T = FooElement
func getElements() -> [T] {
return [T()]
}
}
class FooElement: Element {
// ...
}
But when I try to create a variable like this:
let a: ElementGenerator = FooElementGenerator()
a new error appears:
Protocol 'ElementGenerator' can only be used as a generic constraint because it has Self or associated type requirements
When implementing protocol methods, the return type must be same but you may return child class object like this;
protocol ElementGenerator {
func getElements() -> [Element]
}
//#objc for bridging in objective C
#objc protocol Element {
// ...
}
// Implement
class FooElementGenerator: NSObject,ElementGenerator {
override init() {
super.init();
//--
let fooElements:[FooElement] = self.getElements() as! [FooElement]
}
func getElements() -> [Element] {
// Generate elements here
return [FooElement()]
}
}
class FooElement:NSObject, Element {
// ...
override init() {
super.init();
//--
NSLog("FooElement init");
}
}
The error message in the second case is given since you have defined ElementGenerator with an “Associated Type”, and this means that you can only use it in giving constraints for types.
For instance, if you need to have a function defined for generic ElementGenerator values, you could write something like this:
func f<T1:ElementGenerator>(elemGenerator:T1) -> Element {
return elemGenerator.getElements()[0]
}
var a : Element = FooElementGenerator()
var b : Element = BarElementGenerator()
var x : Element = f(a)
var y : Element = f(b)
var z : FooElement = f(a) as! FooElement