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

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

Related

JSONEncoder works for [String:String] fails for [String:Codable] [duplicate]

Why doesn't this Swift code compile?
protocol P { }
struct S: P { }
let arr:[P] = [ S() ]
extension Array where Element : P {
func test<T>() -> [T] {
return []
}
}
let result : [S] = arr.test()
The compiler says: "Type P does not conform to protocol P" (or, in later versions of Swift, "Using 'P' as a concrete type conforming to protocol 'P' is not supported.").
Why not? This feels like a hole in the language, somehow. I realize that the problem stems from declaring the array arr as an array of a protocol type, but is that an unreasonable thing to do? I thought protocols were there exactly to help supply structs with something like a type hierarchy?
Why don't protocols conform to themselves?
Allowing protocols to conform to themselves in the general case is unsound. The problem lies with static protocol requirements.
These include:
static methods and properties
Initialisers
Associated types (although these currently prevent the use of a protocol as an actual type)
We can access these requirements on a generic placeholder T where T : P – however we cannot access them on the protocol type itself, as there's no concrete conforming type to forward onto. Therefore we cannot allow T to be P.
Consider what would happen in the following example if we allowed the Array extension to be applicable to [P]:
protocol P {
init()
}
struct S : P {}
struct S1 : P {}
extension Array where Element : P {
mutating func appendNew() {
// If Element is P, we cannot possibly construct a new instance of it, as you cannot
// construct an instance of a protocol.
append(Element())
}
}
var arr: [P] = [S(), S1()]
// error: Using 'P' as a concrete type conforming to protocol 'P' is not supported
arr.appendNew()
We cannot possibly call appendNew() on a [P], because P (the Element) is not a concrete type and therefore cannot be instantiated. It must be called on an array with concrete-typed elements, where that type conforms to P.
It's a similar story with static method and property requirements:
protocol P {
static func foo()
static var bar: Int { get }
}
struct SomeGeneric<T : P> {
func baz() {
// If T is P, what's the value of bar? There isn't one – because there's no
// implementation of bar's getter defined on P itself.
print(T.bar)
T.foo() // If T is P, what method are we calling here?
}
}
// error: Using 'P' as a concrete type conforming to protocol 'P' is not supported
SomeGeneric<P>().baz()
We cannot talk in terms of SomeGeneric<P>. We need concrete implementations of the static protocol requirements (notice how there are no implementations of foo() or bar defined in the above example). Although we can define implementations of these requirements in a P extension, these are defined only for the concrete types that conform to P – you still cannot call them on P itself.
Because of this, Swift just completely disallows us from using a protocol as a type that conforms to itself – because when that protocol has static requirements, it doesn't.
Instance protocol requirements aren't problematic, as you must call them on an actual instance that conforms to the protocol (and therefore must have implemented the requirements). So when calling a requirement on an instance typed as P, we can just forward that call onto the underlying concrete type's implementation of that requirement.
However making special exceptions for the rule in this case could lead to surprising inconsistencies in how protocols are treated by generic code. Although that being said, the situation isn't too dissimilar to associatedtype requirements – which (currently) prevent you from using a protocol as a type. Having a restriction that prevents you from using a protocol as a type that conforms to itself when it has static requirements could be an option for a future version of the language
Edit: And as explored below, this does look like what the Swift team are aiming for.
#objc protocols
And in fact, actually that's exactly how the language treats #objc protocols. When they don't have static requirements, they conform to themselves.
The following compiles just fine:
import Foundation
#objc protocol P {
func foo()
}
class C : P {
func foo() {
print("C's foo called!")
}
}
func baz<T : P>(_ t: T) {
t.foo()
}
let c: P = C()
baz(c)
baz requires that T conforms to P; but we can substitute in P for T because P doesn't have static requirements. If we add a static requirement to P, the example no longer compiles:
import Foundation
#objc protocol P {
static func bar()
func foo()
}
class C : P {
static func bar() {
print("C's bar called")
}
func foo() {
print("C's foo called!")
}
}
func baz<T : P>(_ t: T) {
t.foo()
}
let c: P = C()
baz(c) // error: Cannot invoke 'baz' with an argument list of type '(P)'
So one workaround to to this problem is to make your protocol #objc. Granted, this isn't an ideal workaround in many cases, as it forces your conforming types to be classes, as well as requiring the Obj-C runtime, therefore not making it viable on non-Apple platforms such as Linux.
But I suspect that this limitation is (one of) the primary reasons why the language already implements 'protocol without static requirements conforms to itself' for #objc protocols. Generic code written around them can be significantly simplified by the compiler.
Why? Because #objc protocol-typed values are effectively just class references whose requirements are dispatched using objc_msgSend. On the flip side, non-#objc protocol-typed values are more complicated, as they carry around both value and witness tables in order to both manage the memory of their (potentially indirectly stored) wrapped value and to determine what implementations to call for the different requirements, respectively.
Because of this simplified representation for #objc protocols, a value of such a protocol type P can share the same memory representation as a 'generic value' of type some generic placeholder T : P, presumably making it easy for the Swift team to allow the self-conformance. The same isn't true for non-#objc protocols however as such generic values don't currently carry value or protocol witness tables.
However this feature is intentional and is hopefully to be rolled out to non-#objc protocols, as confirmed by Swift team member Slava Pestov in the comments of SR-55 in response to your query about it (prompted by this question):
Matt Neuburg added a comment - 7 Sep 2017 1:33 PM
This does compile:
#objc protocol P {}
class C: P {}
func process<T: P>(item: T) -> T { return item }
func f(image: P) { let processed: P = process(item:image) }
Adding #objc makes it compile; removing it makes it not compile again.
Some of us over on Stack Overflow find this surprising and would like
to know whether that's deliberate or a buggy edge-case.
Slava Pestov added a comment - 7 Sep 2017 1:53 PM
It's deliberate – lifting this restriction is what this bug is about.
Like I said it's tricky and we don't have any concrete plans yet.
So hopefully it's something that language will one day support for non-#objc protocols as well.
But what current solutions are there for non-#objc protocols?
Implementing extensions with protocol constraints
In Swift 3.1, if you want an extension with a constraint that a given generic placeholder or associated type must be a given protocol type (not just a concrete type that conforms to that protocol) – you can simply define this with an == constraint.
For example, we could write your array extension as:
extension Array where Element == P {
func test<T>() -> [T] {
return []
}
}
let arr: [P] = [S()]
let result: [S] = arr.test()
Of course, this now prevents us from calling it on an array with concrete type elements that conform to P. We could solve this by just defining an additional extension for when Element : P, and just forward onto the == P extension:
extension Array where Element : P {
func test<T>() -> [T] {
return (self as [P]).test()
}
}
let arr = [S()]
let result: [S] = arr.test()
However it's worth noting that this will perform an O(n) conversion of the array to a [P], as each element will have to be boxed in an existential container. If performance is an issue, you can simply solve this by re-implementing the extension method. This isn't an entirely satisfactory solution – hopefully a future version of the language will include a way to express a 'protocol type or conforms to protocol type' constraint.
Prior to Swift 3.1, the most general way of achieving this, as Rob shows in his answer, is to simply build a wrapper type for a [P], which you can then define your extension method(s) on.
Passing a protocol-typed instance to a constrained generic placeholder
Consider the following (contrived, but not uncommon) situation:
protocol P {
var bar: Int { get set }
func foo(str: String)
}
struct S : P {
var bar: Int
func foo(str: String) {/* ... */}
}
func takesConcreteP<T : P>(_ t: T) {/* ... */}
let p: P = S(bar: 5)
// error: Cannot invoke 'takesConcreteP' with an argument list of type '(P)'
takesConcreteP(p)
We cannot pass p to takesConcreteP(_:), as we cannot currently substitute P for a generic placeholder T : P. Let's take a look at a couple of ways in which we can solve this problem.
1. Opening existentials
Rather than attempting to substitute P for T : P, what if we could dig into the underlying concrete type that the P typed value was wrapping and substitute that instead? Unfortunately, this requires a language feature called opening existentials, which currently isn't directly available to users.
However, Swift does implicitly open existentials (protocol-typed values) when accessing members on them (i.e it digs out the runtime type and makes it accessible in the form of a generic placeholder). We can exploit this fact in a protocol extension on P:
extension P {
func callTakesConcreteP/*<Self : P>*/(/*self: Self*/) {
takesConcreteP(self)
}
}
Note the implicit generic Self placeholder that the extension method takes, which is used to type the implicit self parameter – this happens behind the scenes with all protocol extension members. When calling such a method on a protocol typed value P, Swift digs out the underlying concrete type, and uses this to satisfy the Self generic placeholder. This is why we're able to call takesConcreteP(_:) with self – we're satisfying T with Self.
This means that we can now say:
p.callTakesConcreteP()
And takesConcreteP(_:) gets called with its generic placeholder T being satisfied by the underlying concrete type (in this case S). Note that this isn't "protocols conforming to themselves", as we're substituting a concrete type rather than P – try adding a static requirement to the protocol and seeing what happens when you call it from within takesConcreteP(_:).
If Swift continues to disallow protocols from conforming to themselves, the next best alternative would be implicitly opening existentials when attempting to pass them as arguments to parameters of generic type – effectively doing exactly what our protocol extension trampoline did, just without the boilerplate.
However note that opening existentials isn't a general solution to the problem of protocols not conforming to themselves. It doesn't deal with heterogenous collections of protocol-typed values, which may all have different underlying concrete types. For example, consider:
struct Q : P {
var bar: Int
func foo(str: String) {}
}
// The placeholder `T` must be satisfied by a single type
func takesConcreteArrayOfP<T : P>(_ t: [T]) {}
// ...but an array of `P` could have elements of different underlying concrete types.
let array: [P] = [S(bar: 1), Q(bar: 2)]
// So there's no sensible concrete type we can substitute for `T`.
takesConcreteArrayOfP(array)
For the same reasons, a function with multiple T parameters would also be problematic, as the parameters must take arguments of the same type – however if we have two P values, there's no way we can guarantee at compile time that they both have the same underlying concrete type.
In order to solve this problem, we can use a type eraser.
2. Build a type eraser
As Rob says, a type eraser, is the most general solution to the problem of protocols not conforming to themselves. They allow us to wrap a protocol-typed instance in a concrete type that conforms to that protocol, by forwarding the instance requirements to the underlying instance.
So, let's build a type erasing box that forwards P's instance requirements onto an underlying arbitrary instance that conforms to P:
struct AnyP : P {
private var base: P
init(_ base: P) {
self.base = base
}
var bar: Int {
get { return base.bar }
set { base.bar = newValue }
}
func foo(str: String) { base.foo(str: str) }
}
Now we can just talk in terms of AnyP instead of P:
let p = AnyP(S(bar: 5))
takesConcreteP(p)
// example from #1...
let array = [AnyP(S(bar: 1)), AnyP(Q(bar: 2))]
takesConcreteArrayOfP(array)
Now, consider for a moment just why we had to build that box. As we discussed early, Swift needs a concrete type for cases where the protocol has static requirements. Consider if P had a static requirement – we would have needed to implement that in AnyP. But what should it have been implemented as? We're dealing with arbitrary instances that conform to P here – we don't know about how their underlying concrete types implement the static requirements, therefore we cannot meaningfully express this in AnyP.
Therefore, the solution in this case is only really useful in the case of instance protocol requirements. In the general case, we still cannot treat P as a concrete type that conforms to P.
EDIT: Eighteen more months of working w/ Swift, another major release (that provides a new diagnostic), and a comment from #AyBayBay makes me want to rewrite this answer. The new diagnostic is:
"Using 'P' as a concrete type conforming to protocol 'P' is not supported."
That actually makes this whole thing a lot clearer. This extension:
extension Array where Element : P {
doesn't apply when Element == P since P is not considered a concrete conformance of P. (The "put it in a box" solution below is still the most general solution.)
Old Answer:
It's yet another case of metatypes. Swift really wants you to get to a concrete type for most non-trivial things. [P] isn't a concrete type (you can't allocate a block of memory of known size for P). (I don't think that's actually true; you can absolutely create something of size P because it's done via indirection.) I don't think there's any evidence that this is a case of "shouldn't" work. This looks very much like one of their "doesn't work yet" cases. (Unfortunately it's almost impossible to get Apple to confirm the difference between those cases.) The fact that Array<P> can be a variable type (where Array cannot) indicates that they've already done some work in this direction, but Swift metatypes have lots of sharp edges and unimplemented cases. I don't think you're going to get a better "why" answer than that. "Because the compiler doesn't allow it." (Unsatisfying, I know. My whole Swift life…)
The solution is almost always to put things in a box. We build a type-eraser.
protocol P { }
struct S: P { }
struct AnyPArray {
var array: [P]
init(_ array:[P]) { self.array = array }
}
extension AnyPArray {
func test<T>() -> [T] {
return []
}
}
let arr = AnyPArray([S()])
let result: [S] = arr.test()
When Swift allows you to do this directly (which I do expect eventually), it will likely just be by creating this box for you automatically. Recursive enums had exactly this history. You had to box them and it was incredibly annoying and restricting, and then finally the compiler added indirect to do the same thing more automatically.
If you extend CollectionType protocol instead of Array and constraint by protocol as a concrete type, you can rewrite the previous code as follows.
protocol P { }
struct S: P { }
let arr:[P] = [ S() ]
extension CollectionType where Generator.Element == P {
func test<T>() -> [T] {
return []
}
}
let result : [S] = arr.test()

How should I write this in Swift?

Let's say that I create a protocol like this:
protocol A {
associatedtype T
func computeSomething(with:T) -> Double
}
In my generic typed class, I would like to do something like this:
class B<U> {
var doSomething:A<U>
}
This thing is that this generates an error, but I would like to accept any type that would support computeSomething on my type U but I don't know at all how to do that?
Edit for clarity
Basically if A was a generic struct or class, that would be possible, but what if no default implementation (provided by class or struct) makes sense here and the only thing I want is to ensure that the type does what I want?
Edit #2 (with concrete example)
I wanted to simplify my question which makes it pretty hard to understand so here is a still simplified and fictional problem that probably matches better the issue I am encountering:
I am writing a generic class that processes its generic type T:
class Process<T> { ... }
The class Process itself includes code that processes T, but in order for this code to work, it needs T to conform to some protocols, for instance:
protocol A {
func mixWith(other:A) -> A
}
protocol B {
var isFoo:Bool { get set }
}
So my first approach was to simply require T to conform to those protocols:
class Process<T:<A,B>> { ... }
This looks like the simplest approach and probably is in many cases, but in my case I think that this actually is problematic, for this reason:
First, I may need to process the same type in many different ways, and changing a way a type is being processed often requires changing the actual implementation of protocols A and B for instance in this case, fooProcess and barProcess are both of type Process with generic type MyType:
let fooProcess = Process<MyType>()
let barProcess = Process<MyType>()
But I want fooProcess and barProcess to do different operations which in many cases would require to change the implementation of the A and B protocols of my MyType type and that's simply not possible.
So my first idea was to simply require some closures and variables to be defined so that I wouldn't need protocols anymore and would define the way data is being processed only in my Process class, a little bit like this:
class Process<T> {
//
var mix:(_ lhs:T, _ rhs:T)->(T)
var isFoo:(_ a:T)->(Bool)
...
}
There all of the processing would be directly implemented in my Processing class, again this would have looked like the right solution but now comes another issue, which led me to my associated type approach: it turns out that in many cases, the user of my Process class would want to get some default behaviour implemented by my framework, for instance, I could automatically implement protocol A and B for them as long as their class conformed to protocol X, here is how it did it:
protocol X:A,B {
...
}
extension protocol X {
// Here was my default implementation of A and B, which enabled my user to directly get A and B implemented as long as their type conformed to X
}
By using this method, I would let my user directly choose what they wanted to implement themselves, by conforming to protocol X they would only need to write a little bit of code and let my framework to all of the rest by itself, and if they wanted to implement themselves A or B they still could.
So if I am right, there is no way to do such a thing with my closures implementation.
So for this reason, I thought that an associated type protocol would be a good solution because here I could let my users easily get some default behaviour or write their own, so now we are getting back to my original question:
protocol AProcessing {
associatedtype U
func mix(_ lhs:U, _ rhs:U) -> U
}
protocol BProcessing {
associatedtype U
func isFoo(_ a:U) -> Bool
}
And then do something like that:
class Process<T> {
var aProcessor:AProcessing<T>
var bProcessor:BProcessing<T>
}
Here the advantage compared to closures is that I could write a special class conforming to AProcessing that could provide default implementation, this way:
class AutomaticAProcessing<T:X>:AProcessing { ... }
That would have enabled my users to so something like that:
var processData = Process<SomeType>()
processData.aProcessor = AutomaticAProcessing<SomeType>()
processData.bProcessor = TheirOwnImplemtation
Not only is this not possible in Swift, but it also feels like I am using too many "hacks" to get things done and there should be an easier language feature to do that, unfortunately I don't know what I should use.
I don't think it is possible, because the generic type of the protocol is specified in the class that implements it.
You could write something like this:
class B<U, P: A> where P.T == U {
var someVar: P?
}
But then you would need to specify a second parameter with the specific class. For example:
class C: A {
typealias T = String
func computeSomething(with: String) -> Double {
return 0.0
}
}
let b = B<String, C>()
let c = b.someVar
But it can't return a protocol with specific type in its associatedtype
One way would be to start with an empty generic struct, and then extend it on types where it makes sense:
struct A<T> {}
extension A where T: Base {
func computeSomething(with: T) -> Double {
return 1
}
}
Usage:
protocol Base {}
class B<U: Base> {
let doSomething = A<U>()
func foo(x: U) -> Double {
return doSomething.computeSomething(with: x)
}
}
class Z : Base {}
let x = B<Z>()
let y = x.foo(x: Z())
print(y)
To EDIT #2:
Remove associated types, and it should be workable:
protocol A {}
protocol B {}
protocol AProcessing {
func mix(_ lhs: A, _ rhs: A) -> A
}
protocol BProcessing {
func isFoo(_ a: B) -> Bool
}
Then, your processor:
class Process<T: A & B> {
var aProcessor: AProcessing!
var bProcessor: BProcessing!
func foo(_ a: T) -> Bool {
let x = aProcessor.mix(a, a)
guard let b = x as? B else { return false }
return bProcessor.isFoo(b)
}
}
And usage:
struct AutomaticAProcessing : AProcessing {
func mix(_ lhs: A, _ rhs: A) -> A { return lhs }
}
struct TheirOwnImplemtation : BProcessing {
func isFoo(_ a: B) -> Bool { return false }
}
struct SomeType : A, B {}
var processData = Process<SomeType>()
processData.aProcessor = AutomaticAProcessing()
processData.bProcessor = TheirOwnImplemtation()
let x = SomeType()
let y = processData.foo(x)
print(y)

protocol with same associated type name

If I have two protocols whose associated type happens to be the same, such as
protocol Read {
associatedtype Element
func read() -> Element
}
protocol Write {
associatedtype Element
func write(a: Element)
}
Then I would like to have a class to read integer from and write string to:
class ReadWrite: Read, Write {
func read() -> Int {
return 5
}
func write(a: String) {
print("writing \(a)")
}
}
but the compiler complains and suggests changing String to Int. Ideally the type should be inferred, or at least compiles if I explicitly declare
associatedtype Read.Element = Int
associatedtype Write.Element = String
within ReadWrite. Any work around?
update
Workaround inspired by this question is to create two auxiliary protocols
protocol ReadInt: Read {
associatedtype Element = Int
}
protocol WriteString: Write {
associatedtype Element = String
}
and have the class inherit from these two instead:
class ReadWrite: ReadInt, WriteString {
func read() -> Int {
return 5
}
func write(a: String) {
print("writing \(a)")
}
}
This seems to compile, but I am afraid of any gotcha following this way.
update again
I found the issue in Swift's issue tracker. Anyone require this missing feature (like me) should vote for it. As a comparison, this pattern is possible in Rust, which also supports associated types (although this is not an idiomatic usage).
Another workaround is to create a third, combined protocol:
protocol ReadWrite {
associatedtype R
associatedtype W
func read() -> R
func write(a: W)
}
It's not pretty, since it forces you to redeclare the protocol members, but it does keep it generic (you're not limited to String and Int).

Defining typeliases declared in other protocols

I'm creating a protocol that extends from CollectionType, however, I'm introducing new typealiases that eliminate the need for Element in CollectionType (or rather, they allow me to compute it).
I'll use a simple MapType protocol as an example:
protocol MapType : CollectionType, DictionaryLiteralConvertible {
typealias Key
typealias Value
func updateValue(theNewValue:Value, forKey theKey:Key) -> Value?
}
In the above example, what I really need to be able to do is redefine Element to be the tuple (Key, Value), but I'm not sure how to do this in a protocol rather than a structure or class.
Simply adding typealias Element = (Key, Value) produces no errors, but also doesn't appear to actually do anything within the context of the protocol, for example, the following won't work:
extension MapType {
var firstKey:Key? { return self.generate().next()?.0 }
}
This produces an error, as the generator isn't recognised as returning a tuple (i.e- it has no member .0).
What is the best way to define Element as (Key, Value) in this case, such that I can use it within protocol extensions? Is this even possible?
We can't necessarily force that the Element type inherited from the CollectionType protocol is necessarily a tuple made up of the Key and Value types from the MapType.
However, we can limit our protocol extension to only add the firstKey method to those that do conform to the protocols in such a way using a where statement.
Consider this simplified example:
protocol Base {
typealias Element
func first() -> Element?
}
protocol Child: Base {
typealias Key
typealias Value
func last() -> (Key, Value)?
}
extension Child where Self.Element == (Self.Key, Self.Value) {
var firstKey:Key? { return self.first()?.0 }
}
struct ChildStruct: Child {
func first() -> (String, Int)? {
return ("Foo", 1)
}
func last() -> (String, Int)? {
return ("Bar", 2)
}
}
let c = ChildStruct()
let first = c.first()
let firstKey = c.firstKey
You're basically trying to create a where clause inside of a protocol. That's not possible in Swift today. You can not constrain associated types based on other associated types. Someday maybe, but not today.
You'll need to rethink how you're attacking the problem. The likely solution is to use a generic struct rather than a protocol (otherwise you tend to wind up with a lot of duplicated where clauses all over your code). You can see this recent dotSwift talk for more detailed examples.

Use of typealias syntax within protocols in the Swift standard library

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.