Define a Swift protocol which requires a specific type of sequence
There are two sides to this problem:
Accepting an arbitrary sequence of ints
Returning or storing an arbitrary sequence of ints
In the first case, the answer is to use generics. For example:
func iterateOverInts<SeqInt: SequenceType where SeqInt.Generator.Element == Int>(xs: SeqInt) {
for x in xs {
print(x)
}
}
In the second case, you need a type-eraser. A type-eraser is a wrapper that hides the actual type of some underlying implementation and presents only the interface. Swift has several of them in stdlib, mostly prefixed with the word Any
. In this case you want AnySequence
.
func doubles(xs: [Int]) -> AnySequence<Int> {
return AnySequence( xs.lazy.map { $0 * 2 } )
}
For more on AnySequence
and type-erasers in general, see A Little Respect for AnySequence.
If you need it in protocol form (usually you don't; you just need to use a generic as in iterateOverInts
), the type eraser is also the tool there:
protocol HasSequenceOfInts {
var seq : AnySequence<Int> { get }
}
But seq
must return AnySequence<Int>
. It can't return [Int]
.
There is one more layer deeper you can take this, but sometimes it creates more trouble than it solves. You could define:
protocol HasSequenceOfInts {
typealias SeqInt : IntegerType
var seq: SeqInt { get }
}
But now HasSequenceOfInts
has a typealias
with all the limitations that implies. SeqInt
could be any kind of IntegerType
(not just Int
), so looks just like a constrained SequenceType
, and will generally need its own type eraser. So occasionally this technique is useful, but in your specific case it just gets you basically back where you started. You can't constrain SeqInt
to Int
here. It has to be to a protocol (of course you could invent a protocol and make Int
the only conforming type, but that doesn't change much).
BTW, regarding type-erasers, as you can probably see they're very mechanical. They're just a box that forwards to something else. That suggests that in the future the compiler will be able to auto-generate these type-erasers for us. The compiler has fixed other boxing problems for us over time. For instance, you used to have to create a Box
class to hold enums that had generic associated values. Now that's done semi-automatically with indirect
. We could imagine a similar mechanism being added to automatically create AnySequence
when it's required by the compiler. So I don't think this is a deep "Swift's design doesn't allow it." I think it's just "the Swift compiler doesn't handle it yet."
Requiring, for a protocol, that an instance variable conform to a protocol ; rather than have a specific type
What you're looking for is an associated type. This means exactly what you've described (the required type conforms to a protocol rather than being the existential of that protocol):
protocol CompatibleFloatingPoint {
associatedtype BitPattern: FixedWidthInteger
var bitPattern : BitPattern { get }
}
extension Float: CompatibleFloatingPoint {}
extension Double: CompatibleFloatingPoint {}
For more details, see Associated Types in the Swift Programming Language.
Function that accepts sequence of type
Your question is to do with the difference between generic types and associated types. See here (sections titled "Generic Types", "Associated Types") for a basic explanation of their purposes in Swift. Protocols, like Sequence, use associated types, rather than generic types. Your first code sample would make sense if Sequence
was a concrete class with a generic type - this difference should explain the error message.
As for why protocols use associated types, rather than generic types, see the top answer to this question. Essentially, though they seem to serve the same purpose, associated types are meant to be more flexible and descriptive, where generic types are about implementation. This makes your code sample more verbose, but overall, makes many code samples simpler.
In fact, from the Sequence source code, Sequence
has an associated type Iterator, which conforms to the IteratorProtocol protocol, which in turn has its own associated type Element (which can be any type).
How does Swift infer Sequence requirements when Self implements IteratorProtocol?
Let's start with the implementation of IteratorProtocol.next
. The compiler sees this implementation:
mutating func next() -> Int? {
if count == 0 {
return nil
} else {
defer { count -= 1 }
return count
}
}
And notices that it returns an Int?
. Well, IteratorProtocol.next
is supposed to return a Self.Element?
, so it infers that IteratorProtocol.Element == Int
. Now Coundown
satisfies IteratorProtocol
.
Note that Sequence
and IteratorProtocol
share the associated type Element
. Once Swift figures out the witness for IteratorProtcol.Element
, it's as if you declared a new type alias Element
in Countdown
, and it just so happens that Sequence
requires that Countdown.Element
to exist.
After that, the compiler infers Iterator == Self
. This is so that the default implementation of makeIterator
is available. However, it is quite a mystery how the compiler can infer this, because with only these information, the type can't normally be inferred, as can be shown by creating your own sequence and iterator protocols.
protocol MyIterator {
associatedtype Element
mutating func next() -> Element?
}
protocol MySequence {
associatedtype Element where Element == Iterator.Element
associatedtype Iterator : MyIterator
func makeIterator() -> Iterator
}
extension MySequence where Self == Self.Iterator {
func makeIterator() -> Iterator {
return self
}
}
struct Countdown: MySequence, MyIterator { // doesn't compile
var count: Int
mutating func next() -> Int? {
if count == 0 {
return nil
} else {
defer { count -= 1 }
return count
}
}
}
After looking into the source code, I suspect there might be some compiler magic going on, especially here:
// Provides a default associated type witness for Iterator when the
// Self type is both a Sequence and an Iterator.
extension Sequence where Self: IteratorProtocol {
// @_implements(Sequence, Iterator)
public typealias _Default_Iterator = Self
}
This seems to set a "preferred" type for Iterator
to be inferred as. It seems to be saying "When Iterator
can't be inferred to be anything, try Self
". I can't find _Default_Iterator
anywhere else, which is why I concluded it's compiler magic. The whole purpose of this is to allow you to conform to Sequence
by only conforming to IteratorProtocol
and implementing next
, as the documentation said you can do.
Now that Iterator == Self
, we have also satisfied the constraint on Element
:
associatedtype Element where Self.Element == Self.Iterator.Element
Thus we have shown that Countdown
conforms to Sequence
.
Swift: Type does not conform to protocol 'ArrayLiteralConvertible'
ArrayLiteralConvertible
requires you to implement an initializer of type init(arrayLiteral: Element...)
. Something like this would re-use your initializer that takes a sequence:
init(arrayLiteral: Element...) {
self = Set(arrayLiteral)
}
If you’re doing this in a playground, hit opt-cmd-enter to see more details in the assistant editor than you get just from the error message in the source. It shows the details of all the protocol requirements you aren’t meeting.
By the way, if you declared contents like this:
private var contents: [Element: Bool] = [:]
you wouldn’t need to initialize it in each of your initializers.
Swift, use generic property with different specific types - Reference to generic type requires arguments in
You can specify a protocol for providing Stage
types like so:
protocol StageProvider {
associatedtype T: Stage
func getType() -> T.Type
}
Then make your SomethingThatKnowsAboutTheStages
or any other one conform this protocol:
class SomethingThatKnowsAboutTheStages: StageProvider {
typealias T = SecondStage
func getType() -> T.Type {
SecondStage.self
}
}
Add an initializer for your FooBarController
:
class FooBarController<StageType: Stage>: UIViewController {
convenience init(stage: StageType.Type) {
self.init()
}
}
And finally use all these:
func fooBarScreen<T: StageProvider>(boop: T) {
let controller = FooBarController(stage: boop.getType())
}
Swift Protocol inheriting Protocol method with same name
This is because a non-throwing function is by definition a sub-type of a throwing function
From the Swift Programming Language book
The throws keyword is part of a function’s type, and nonthrowing functions are subtypes of throwing functions. As a result, you can use a nonthrowing function in the same places as a throwing one.
But you can't do it the other way around so the below code will generate an error
protocol Base {
func foo() -> Int
}
protocol Refined: Base {
func foo() throws -> Int //error: Cannot override non-throwing method with throwing method
}
Also note that this is not only for protocols, if you remove the func declaration from Refined
you can still implement the function in Test
as non throwing.
Related Topics
Dynamic/Runtime Dispatch in Swift, or "The Strange Way Structs Behave in One Man's Opinion"
Swiftui: How to Make a Button Open a Url in Safari
Swiftui - in Sheet Have a Fixed Continue Button That Is Not Scrollable
How to Embed Third Party Framework on Ionic Capacitor Custom Plugin
How to Create Instance Variable and Class Variable of the Same Name
Realitykit - Adding Modelentity to an Argeoanchor
Swiftui Out of Index When Deleting an Array Element in Foreach
How to Save the Attributed String (Text) into File (Swift, Cocoa)
Uibarbuttonitem Doesn't Work When Created as a Property, But Does When Created in a Function
Swift 3 - Uibutton Adding Settitle from Plist and Database
How to Open a Screen Directly in Xcuitest
Swift/Firebase - Sort Posts in Tableview by Date
Core Data Predicate Not Working
Launch Sudo Command from MACos App Swift