Cannot specify associated type through protocol extension

As expected, an associated type can be specified either in the protocol or in the conforming type(s).

So this compiles:

protocol Fooable {
    typealias Bar = Int
}

struct SomeFoo : Fooable {
}


As does this:

protocol Fooable {
    typealias Bar
}

struct SomeFoo : Fooable {
    typealias Bar = Int
}


But for some reason associated types cannot be specified through a protocol extension, ie:

protocol Fooable {
    typealias Bar
}

extension Fooable {
    typealias Bar = Int
}

struct SomeFoo : Fooable { // Error: Type 'SomeFoo' does not conform to protocol 'Fooable'
}


Is this a bug (Xcode 7 and Xcode 7.1 beta 2)?


(This is of course a bare bones example of the problem. In my actual use case the associated type is being derived from another type (rather than just being eg Int) and it makes more sense to specify that relationship in a protocol extension than repeating it in every concrete type.)

Also, can someone explain why the following works while the last example above doesn't:

protocol Fooable {
    //typealias Bar  <-- Works only if this line is commented out.
}

extension Fooable {
    typealias Bar = Int
}

struct SomeFoo : Fooable {
}

print(SomeFoo.Bar.self) // Prints Int

?

As you already wrote, associated types cannot be specified through a protocol extension.

extension Fooable {
    typealias Bar = Int
}

This is a simple typealias declaration, which is valid for all types conforming to Fooable.


So, in this case.

protocol Fooable {
    typealias Bar
}
extension Fooable {
    typealias Bar = Int
}

Fooable looks like having two different things with the same name, associated type `Bar` and typealias `Bar`.


Because adding one line to the protocol Foo, generates the following message:

protocol Fooable {
    typealias Bar
    func generateBar() -> Bar //-> 'Bar' is ambiguous for type lookup in this context
}
extension Fooable {
    typealias Bar = Int
}

This seems to be a bug.

Thanks, I thought this looked like a bug too, so I've filed:

22772123


But note that the following currently compiles and works as (possibly) expected:

protocol Fooable {
  // typealias Bar              // <-- Have to comment this out or it will not compile.
  // func generateBar() -> Bar  // <-- Same here (of course).
}
extension Fooable {
    typealias Bar = Int
    func generateBar() -> Bar { return 1234 }
}

struct FooUsingDefaultBar : Fooable {
}
struct FooUsingSpecialBar : Fooable {
    typealias Bar = Double
    func generateBar() -> Bar { return 1.2 }
}

print(FooUsingDefaultBar().generateBar()) // Prints 1234 (as possibly expected)
print(FooUsingSpecialBar().generateBar()) // Prints 1.2  (as possibly expected)


If the bug is fixed, would that mean that the following should also compile (which it currently doesn't):

protocol Fooable {
    typealias Bar // All concrete types that conforms to Fooable must have an associated type called Bar.
    func generateBar() -> Bar // And a function like this, returning a Bar.
}
extension Fooable { // Default implementation for concrete Fooable types that don't implement their special Bar and generateBar().
    typealias Bar = Int
    func generateBar() -> Bar { return 1234 }
}

struct FooUsingDefaultBar : Fooable {
}
struct FooUsingSpecialBar : Fooable {
    func generateBar() -> Double { return 1.2 } // Type inference means Bar = Double, so no need to explicitly specify "typealias Bar = Double".
}

print(FooUsingDefaultBar().generateBar()) // 1234
print(FooUsingSpecialBar().generateBar()) // 1.2

print(FooUsingDefaultBar.Bar.self) // Int
print(FooUsingSpecialBar.Bar.self) // Double


Or is it the other way around, that if the bug is fixed, then neither of these two examples would compile?


I think the bottom example here makes sense and should compile, the reason being that a protocol extension is a default implementation (See The Swift Programming Language: Providing Default Implementations).


If it doesn't make sense, then what is the reason for not allowing a default implementation to specify a default associated type?

Oh, and this currently compiles and works as expected:

protocol Fooable {
    typealias Bar
    func generateBar() -> Bar
}
extension Fooable {
    func generateBar() -> Int { return 1234 }
}

struct FooUsingDefaultBar : Fooable {
}
struct FooUsingSpecialBar : Fooable {
    func generateBar() -> Double { return 1.2 }
}

print(FooUsingDefaultBar().generateBar()) // 1234
print(FooUsingSpecialBar().generateBar()) // 1.2

print(FooUsingDefaultBar.Bar.self) // Int
print(FooUsingSpecialBar.Bar.self) // Double

It's exactly the same as the bottom example in my previous post, except that I have removed

"typealias Bar = Int" from the protocol extension, and instead let the compiler infer the fact that the default type for the associated type Bar should be Int.

So evidently the compiler can infer it from eg "func generateBar() -> Int". I think it should be ok to just specify it explicitly too, without needing a function or computed property to state the same fact implicitly.

You find an interesting, useful to explain, example.


In your last example:

protocol Fooable {
    typealias Bar
    func generateBar() -> Bar
}
extension Fooable {
    func generateBar() -> Int { return 1234 }
}

You declare Fooable.associatedtype.Bar (not specified), and in the extension declaring the default type of Fooable.associatedtype.Bar = Int.

After that:

struct FooUsingSpecialBar : Fooable {
    func generateBar() -> Double { return 1.2 }
}

You can define a struct with FooUsingSpecialBar.associatedtype.Bar = Double, using type inference.


And in your previous example:

protocol Fooable {
    typealias Bar
    func generateBar() -> Bar
}
extension Fooable {
    typealias Bar = Int
    func generateBar() -> Bar { return 1234 }
}

You delare Fooable.assosiatedtype.Bar, and in the extenssion declaring Fooable.typealiase.Bar = Int and the default type of Fooable.associatedtype.Bar = (ambiguous).Bar . As already noted, this causes a name conflict, and you cannot use it as it is.


But you can specify defaults of assosicated types, in protocol context.

So, this seems to work:

protocol Fooable {
    typealias Bar = Int
    func generateBar() -> Bar
}
extension Fooable {
    func generateBar() -> Int { return 1234 }
}
struct FooUsingDefaultBar : Fooable {
}
struct FooUsingSpecialBar : Fooable {
    func generateBar() -> Double { return 1.2 }
}
print(FooUsingDefaultBar().generateBar()) // 1234
print(FooUsingSpecialBar().generateBar()) // 1.2
print(FooUsingDefaultBar.Bar.self) // Int
print(FooUsingSpecialBar.Bar.self) // Double


EDIT: added a word `ambiguous`.

Cannot specify associated type through protocol extension
 
 
Q