Constraining an associated type from an inherited protocol?

Writing "constrained versions" of existing protocols seems like a basic and useful thing to do, yet I keep running into problems when trying. I'll try to explain what I mean by an example:

Let's say we need a protocol that is exactly like GeneratorType except that its Element must be an IntegerType.

I might be missing something but I'm guessing that this is the way to express that in Swift:

protocol IntegerGeneratorType : GeneratorType {
    typealias Element: IntegerType
}

We could make a GeneratorType based protocol with even harder constraints on its Element, eg that it must be Int:

protocol IntGeneratorType : GeneratorType {
    typealias Element = Int
}


Now, let's add a default implementation of a method called squaredNext to the latter example protocol:

extension IntGeneratorType {
    mutating func squaredNext() -> Int? {
        guard let someNext = next() else { return nil }
        return someNext * someNext // Error: Binary operator '*' cannot be applied to two 'Self.Element' operands.
    }
}


I can't see the reason for that error. It seems like the type checker can't see that IntGeneratorType.Element == Int, even though it's right there in the declaration of IntGeneratorType.


A workaround is to add a where clause to the extension:

extension IntGeneratorType where Element == Int {// <-- Added where Element == Int
    mutating func squaredNext() -> Int? {
        guard let someNext = next() else { return nil }
        return someNext * someNext // <-- Which makes this compile.
    }
}


I don't understand why this workaround works. I mean, IntGeneratorType.Element cannot be anything but an Int, and the solution here is apparently to restate that fact.


(This workaround still has problems which I won't go into here, it suffices to say that I keep running into this sort of confusion with protocols and especially associated types. The rules for how Swift resolves associated types seems impenetrable to me.)


Can someone shed some light on this?

Answered by SevenTenEleven in 86055022

Using "typealias Foo = Bar" in a protocol doesn't constrain an associated type; it merely sets a default for it. Swift doesn't currently have a formal way to restrict existing associated types in inherited protocols.


I think we already have requests covering the pieces of this, so no need to file a new one.

Accepted Answer

Using "typealias Foo = Bar" in a protocol doesn't constrain an associated type; it merely sets a default for it. Swift doesn't currently have a formal way to restrict existing associated types in inherited protocols.


I think we already have requests covering the pieces of this, so no need to file a new one.

Thanks again for helping me understand what I had misunderstood here aswell: https://forums.developer.apple.com/message/86072#86072


I suppose a (somewhat ugly) workaround would be something like this:

protocol SomeProtocolThatOnlyIntConformsTo {}
extension Int: SomeProtocolThatOnlyIntConformsTo {}
protocol IntGeneratorType : GeneratorType {
    typealias Element: SomeProtocolThatOnlyIntConformsTo
}
Constraining an associated type from an inherited protocol?
 
 
Q