Use of typealias syntax within protocols in the Swift standard library - swift

In the Swift programming guide from Apple, it is described how to use the typealias keyword within protocols (from the section on Generics)
protocol Container {
typealias ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
which is then implemented:
struct IntStack: Container {
typealias ItemType = Int // can sometimes be left out and inferred by the compiler
mutating func append(item: Int) {
self.push(item)
}
// redacted
}
However, a significantly different use case is found in the Swift standard lib, e.g
public protocol ForwardIndexType : _Incrementable {
typealias Distance : _SignedIntegerType = Int
// redacted
}
or
public protocol CollectionType : Indexable, SequenceType {
typealias Generator : GeneratorType = IndexingGenerator<Self>
public func generate() -> Self.Generator
// redacted
}
together with:
extension CollectionType where Generator == IndexingGenerator<Self> {
public func generate() -> IndexingGenerator<Self>
}
What does this syntax represent? It appears that the typealias is both declared, restricted (e.g. to GeneratorType) and assigned, all at once? What does this mean and why is it so? I expected to see assignment (=) only in implementing client code.
My understanding of typealias is that it represents a type, that is 'filled in' by the implementing code (as per generics) yet here it seems to implement a type for the typealias in the declaration, even though this is also done in the extension (where I would expect it).

Take a look at this answer. Use of a colon shows inheritance, use of an equals sign shows assignment.
In my understanding this means the following:
typealias X // defines associated type X for subclasses to override
typealias X: Y // defines associated type X and requires that it conform to Y
typealias X = Z // defines associated type X with a default of type Z
typealias X: Y = Z // defines associated type X with a default of type Z and requires that any overrides conform to Y
My interpretation seems to be supported by this article on Swift generics:
An associated type is declared by a protocol using the typealias
keyword. It normally set by an item that conforms to that protocol,
although you can supply a default. Like type parameters, an
associated type can be used as a token when building generic type
rules.
The use of the keyword typealias can be misleading for defining associated types and may be replaced by associatedtype in the future.

Related

Swift: What is the difference between a typealias and an associatedtype with a value in a protocol?

In Swift, the following code compiles without issue.
protocol P1 {
associatedtype T = Int
}
protocol P2 {
typealias T = Int
}
To me, these appear to behave almost identically. The only difference I have noticed is that there are additional restrictions on when you can use P1 because it has an associated type. In particular, let x: P1 is an error while let x: P2 is fine.
What is the actual difference between these two protocols? Are they treated differently in compiled code? Lastly, is there ever an advantage to using P1 rather than P2?
Edit for clarity:
I know the working difference between associated types and type aliases, so I am surprised that you are even allowed to give an associated type a fixed value. That seems to defeat the entire purpose of an associated type. I am wondering if there is any utility to giving an associated type a fixed value, and I am wondering if these two protocols are different once compiled.
In the code you have written there isn't really a functional difference because you have set the associatedtype as Int.
To get more powerful usage out of them you can use the associatedtype as a pseudo generic constraint.
So you might write it like this...
protocol P1 {
associatedtype Item: Equatable
var itemArray: [Item] { get set }
mutating func add(item: Item)
}
extension P1 {
mutating func add(item: Item) {
itemArray.append(item)
}
}
struct StructWithStrings: P1 {
var itemArray: [String]
}
struct StructWithInts: P1 {
var itemArray: [Int]
}
Because they both conform to P1 and they both set their array type to Equatable types. The compiler can infer the correct type of the add(item: Item) function and help at compile time.
In contrast to this... typealias is only really used to change the name of some type for convenience. For instance you might use a closure a lot like... (Data?, Error?, URLResponse) -> () and it would be long to write it many times but also loses some of the meaning. So you could do...
typealias DownloadResponse = (Data?, Error?, URLResponse) -> ()
and replace all the usages with DownloadResponse.
There are loads of excellent resources about associatedtype in Swift...
Hacking With Swift
Natasha the Robot
Medium
It's basically the same, the main difference is that you don't have to specify the type, as the code below. But it's a problem related to Swift 2.2, when typealias became deprecated in protocols.
protocol P1 {
associatedtype T = Int
func anyMethod(value: T) -> T
}
struct A: P1 {
func anyMethod(value: P1.T) -> P1.T {
1000 + value
}
}
More information here

Why do I get the error “Protocol … can only be used as a generic constraint because it has Self or associated type requirements”?

I wrote an extension onto Int as below.
extension Int {
func squared () -> Int {
return self * self
}
}
print(10.squared()) // works
The above code works. Now I want to extend the IntegerType protocol so that Int, UInt, Int64, etc would all conform. My code is as below.
extension IntegerType {
func squared () -> IntegerType { // this line creates error
return self * self
}
}
I get error:
Protocol 'IntegerType' can only be used as a generic constraint because it has Self or associated type requirements
I already saw this question and its video & this question, still couldn't understand. I only understood that there is some associatedType which in this case is Self but couldn't connect the dots. I feel like also my lack of knowledge on the Generics subject is also a reason...
Can someone elaborate a bit on the subject and why does the extension create an error?
You just have to return Self
edit/update:
Note: You can extend all numeric types (Integer & FloatingPoint) in Swift 4 extending the Numeric Protocol
Swift 4
extension Numeric {
func squared() -> Self {
return self * self
}
}
Swift 3
extension Integer {
func squared() -> Self {
return self * self
}
}
A function return type can only be a concrete Type.
The point is Type. Anything struct, class or Protocols that are completely defined in themselves are pure Type. However when a protocol or struct depend on another Generic Type Placeholder such as T, then this is a partial type.
Type are a data construct that compiler has to allocate certain memory.
So something like this:
let a = Array<T>() or let b = T is not sufficient information for the compiler to deduce at compile time.
Hence, this wont work.
extension IntegerType {
func squared () -> IntegerType { // this line creates error
return self * self
}
}
Here, IntegerType is a partial type. It is a generic protocol that only when conformed can then we know the exact type. Similar to Array. Array itself is not a type. Its a generic container. Only when someone creates it with Array() or Array()... then it has a type.
The same happened with you.
public protocol IntegerType : _IntegerType, RandomAccessIndexType {
then again,
public protocol RandomAccessIndexType : BidirectionalIndexType, Strideable, _RandomAccessAmbiguity {
#warn_unused_result
public func advancedBy(n: Self.Distance) -> Self
then again,
public protocol _RandomAccessAmbiguity {
associatedtype Distance : _SignedIntegerType = Int
}
Hence, as RandomAccessIndexType has Self requirement meaning until and unless someone conforms to it, Self is unknown placeholder. It is partial Type.
Since IntegerType conforms to the RandomAccessIndexType and _RandomAccessAmbuiguity which requires Distance associated type too.
Hence you cant do this too
let a: IntegerType = 12
Again IntegerType needs to know Self and Distance (associatedType).
Int however provides the details like so
public struct Int : SignedIntegerType, Comparable, Equatable {
/// A type that can represent the number of steps between pairs of
/// values.
public typealias Distance = Int
Hence you can do such
let a:Int = 10
because it provides Self for SignedIntegerType and Distance for its other counterpart.
Simply put it:
A partial type cannot be used where a concrete type can be. A partial type are good for other generics and constraining them.

Swift: Any Kind of sequence as a function parameter

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()
}
}
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 underlying SequenceType.
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
}

Self in protocol

I am learning swift and playing with Xcode.
and I always dig into the definitions. I have seen that:
public protocol GeneratorType {
typealias Element
#warn_unused_result
public mutating func next() -> Self.Element?
}
A struct that conforming this protocol:
public struct IndexingGenerator<Elements : Indexable> : GeneratorType, SequenceType {
public init(_ elements: Elements)
public mutating func next() -> Elements._Element?
}
I know 'Self' means that returning the conforming type. But what does 'Self.Element' mean?
and the function that implemented the requirement that returning 'Elements._Element?', I can’t see 'Elements._Element?' is equal to 'Self.Element?'.
Can anyone explain to me this?
and tell me more about this. thank you.
Self.Element refers to the concrete type that any type implementing GeneratorType protocol will declare as its Element typealias.
For example, in this generator of Fibonacci numbers:
struct Fibonacci: GeneratorType {
typealias Element = Int
private var value: Int = 1
private var previous: Int = 0
mutating func next() -> Element? {
let newValue = value + previous
previous = value
value = newValue
return previous
}
}
... you implement GeneratorType protocol and indicate what will be its Element typealias (Int in this case), and that's the type that generator's next() will be returning (well, actually the optional of that type).
Quite often, though, you would not have to explicitly specify typealiases when implementing parametrised protocols, as Swift is smart enough to infer them for you. E.g. for the Fibonacci numbers generator from the above example the following will also do:
struct Fibonacci: GeneratorType {
private var value: Int = 1
private var previous: Int = 0
mutating func next() -> Int? {
let newValue = value + previous
previous = value
value = newValue
return previous
}
}
... Swift knows from the signature of next() that it returns Int?, and that GeneratorType implementors also must have next() in their to-do list, and that these methods must return Element? types. So, Swift just puts 2 and 2 together, and infers that Element? must be the same thing as Int?, and therefore Element == Int.
About this:
public struct IndexingGenerator<Elements : Indexable> : GeneratorType, SequenceType {
public init(_ elements: Elements)
public mutating func next() -> Elements._Element?
}
Here we have four things going on:
We declare generic type IndexingGenerator that takes a parameter-type called Elements.
This Elements type has a constraint that it must implement Indexable protocol.
The generator that we implement is supposed to return values of the type that is accessible via Indexable interface of Elements, which is known to IndexingGenerator via dot-syntax as Elements._Element.
Swift infers that Element of IndexingGenerator is the same thing as Elements._Element.
So, essentially the above delclaration is equivalent to:
public struct IndexingGenerator<Elements : Indexable> : GeneratorType, SequenceType {
public typealias Element = Elements._Element
public init(_ elements: Elements)
public mutating func next() -> Element?
}
Finally, if curious why _Element and not just Element like in GeneratorType, here is what they write in the open-source Swift repository (under swift/stdlib/public/core/Collection.swift):
The declaration of _Element and subscript here is a trick used to break a cyclic conformance/deduction that Swift can't handle. We need something other than a CollectionType.Generator.Element that can be used as IndexingGenerator<T>'s Element. Here we arrange for the CollectionType itself to have an Element type that's deducible from its subscript. Ideally we'd like to constrain this Element to be the same as CollectionType.Generator.Element, but we have no way of expressing it today.

protocol associated type typealias assignment compile error

Following code:
protocol SomeProtocol {
typealias SomeType = Int // used typealias-assignment
func someFunc(someVar: SomeType)
}
class SomeClass: SomeProtocol {
func someFunc(someVar: SomeType) {
print(someVar)
}
}
gives compile-time error:
Use of undeclared type 'SomeType'
Adding, say typealias SomeType = Double, to the SomeClass resolves the error.
The question is, what's the point of typealias-assignment part (which is optional btw) of protocol associated type declaration though?
In this case the assignment of Int to the typealias is equal to no assignment because it gets overridden by your conforming type:
// this declaration is equal since you HAVE TO provide the type for SomeType
protocol SomeProtocol {
typealias SomeType
func someFunc(someVar: SomeType)
}
Such an assignment provides a default type for SomeType which gets overridden by your implementation in SomeClass, but it is especially useful for protocol extensions:
protocol Returnable {
typealias T = Int // T is by default of type Int
func returnValue(value: T) -> T
}
extension Returnable {
func returnValue(value: T) -> T {
return value
}
}
struct AStruct: Returnable {}
AStruct().returnValue(3) // default signature: Int -> Int
You get the function for free only by conforming to the protocol without specifying the type of T. If you want to set your own type write typealias T = String // or any other type in the struct body.
Some additional notes about the provided code example
You solved the problem because you made it explicit which type the parameter has. Swift also infers your used type:
class SomeClass: SomeProtocol {
func someFunc(someVar: Double) {
print(someVar)
}
}
So SomeType of the protocol is inferred to be Double.
Another example where you can see that SomeType in the class declaration doesn't refer to to the protocol:
class SomeClass: SomeProtocol {
typealias Some = Int
func someFunc(someVar: Some) {
print(someVar)
}
}
// check the type of SomeType of the protocol
// dynamicType returns the current type and SomeType is a property of it
SomeClass().dynamicType.SomeType.self // Int.Type
// SomeType gets inferred form the function signature
However if you do something like that:
protocol SomeProtocol {
typealias SomeType: SomeProtocol
func someFunc(someVar: SomeType)
}
SomeType has to be of type SomeProtocol which can be used for more explicit abstraction and more static code whereas this:
protocol SomeProtocol {
func someFunc(someVar: SomeProtocol)
}
would be dynamically dispatched.
There is some great information in the documentation on "associated types" in protocols.
Their use is abundant throughout the standard library, for an example reference the SequenceType protocol, which declares a typealias for Generator (and specifies that it conforms to GeneratorType). This allows the protocol declaration to refer to that aliased type.
In your case, where you used typealias SomeType = Int, perhaps what you meant was "I want SomeType to be constrained to Integer-like behavior because my protocol methods will depend on that constraint" - in which case, you may want to use typealias SomeType: IntegerType in your protocol, and then in your class go on to assign a type to that alias which conforms to IntegerType.
UPDATE
After opening a bug w/ Apple on this and having had extensive discussion around it, I have come to an understanding of what the base issue is at the heart of this:
when conforming to a protocol, you cannot directly refer to an associated type that was declared only within that protocol
(note, however, that when extending a protocol the associated type is available, as you would expect)
So in your initial code example:
protocol SomeProtocol {
typealias SomeType = Int
func someFunc(someVar: SomeType)
}
class SomeClass: SomeProtocol {
func someFunc(someVar: SomeType) { // use of undeclared type "SomeType"
print(someVar)
}
}
...the error re: "use of undeclared type" is correct, your class SomeClass has not declared the type SomeType
However, an extension to SomeProtocol has access to the associated type, and can refer to it when providing an implementation:
(note that this requires using a where clause in order to define the requirement on the associated type)
protocol SomeProtocol {
typealias SomeType = Int
func someFunc(someVar: SomeType)
}
extension SomeProtocol where SomeType == Int {
func someFunc(someVar: SomeType) {
print("1 + \(someVar) = \(1 + someVar)")
}
}
class SomeClass: SomeProtocol {}
SomeClass().someFunc(3) // => "1 + 3 = 4"
There is great article that actually gives you answer for your question. I suggest everyone to read it to get into type-aliases and some more advanced stuff that comes up when you use it.
Citation from website:
Conceptually, there is no generic protocols in Swift. But by using
typealias we can declare a required alias for another type.