I have created my custom sequence type and I want the function to accept any kind of sequence as a parameter. (I want to use both sets, and my sequence types on it)
Something like this:
private func _addToCurrentTileset(tilesToAdd tiles: SequenceType)
Is there any way how I can do it?
It seems relatively straightforward, but I can't figure it out somehow. Swift toolchain tells me:
Protocol 'SequenceType' can only be used as a generic constraint because it has Self or associated type requirements
, and I don't know how to create a protocol that will conform to SequenceType and the Self requirement from it.
I can eliminate the associatedType requirement with, but not Self:
protocol EnumerableTileSequence: SequenceType {
associatedtype GeneratorType = geoBingAnCore.Generator
associatedtype SubSequence: SequenceType = EnumerableTileSequence
}
Now if say I can eliminate self requirement, then already with such protocol definition other collectionType entities like arrays, sets won't conform to it.
Reference: my custom sequences are all subclasses of enumerator type defined as:
public class Enumerator<T> {
public func nextObject() -> T? {
RequiresConcreteImplementation()
}
}
extension Enumerator {
public var allObjects: [T] {
return Array(self)
}
}
extension Enumerator: SequenceType {
public func generate() -> Generator<T> {
return Generator(enumerator: self)
}
}
public struct Generator<T>: GeneratorType {
let enumerator: Enumerator<T>
public mutating func next() -> T? {
return enumerator.nextObject()
}
}
Every function in Swift has a type, consisting of the function's parameter types and return type. You can use this type like any other type in Swift, which makes it easy to pass functions as parameters to other functions, and to return functions from functions.
Swift inout parameter is a parameter that can be changed inside the function where it's passed into. To accept inout parameters, use the inout keyword in front of an argument. To pass a variable as an inout parameter, use the & operator in front of the parameter.
Swift – Assign Function to a Variable To assign function to a variable in Swift, declare a variable that takes specific set/type of parameters and return a specific type of value. Then we can assign a function that has same type of parameters and return value to this variable.
The Swift Programming Language guide has the following suggestion: “The use of external parameter names can allow a function to be called in an expressive, sentence-like manner, while still providing a function body that is readable and clear in intent.”
The compiler is telling you the answer: "Protocol 'Sequence' can only be used as a generic constraint because it has Self or associated type requirements".
You can therefore do this with generics:
private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T) {
...
}
This will allow you to pass in any concrete type that conforms to Sequence
into your function. Swift will infer the concrete type, allowing you to pass the sequence around without lose type information.
If you want to restrict the type of the element in the sequence to a given protocol, you can do:
private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T) where T.Element: SomeProtocol {
...
}
Or to a concrete type:
private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T) where T.Element == SomeConcreteType {
...
}
If you don't care about the concrete type of the sequence itself (useful for mixing them together and in most cases storing them), then Anton's answer has got you covered with the type-erased version of Sequence
.
You can use type-eraser AnySequence
for that:
A type-erased sequence.
Forwards operations to an arbitrary underlying sequence having the same
Element
type, hiding the specifics of the underlyingSequenceType
.
E.g. if you will need to store tiles as an internal property or somehow use its concrete type in the structure of you object then that would be the way to go.
If you simply need to be able to use the sequence w/o having to store it (e.g. just map
on it), then you can simply use generics (like @originaluser2 suggests). E.g. you might end up with something like:
private func _addToCurrentTileset<S: SequenceType where S.Generator.Element == Tile>(tilesToAdd tiles: S) {
let typeErasedSequence = AnySequence(tiles) // Type == AnySequence<Tile>
let originalSequence = tiles // Type == whatever type that conforms to SequenceType and has Tile as its Generator.Element
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With