"value type" constrained protocol extension

Hi there,

I was trying something I thought was pretty trivial today, and found myself not being able to do it. This is about implementing a protocol extension to define a default behavior. I'm not able to constraint this default implementation with a "same-type" constraint related to a "value type".

Here is the code:

protocol Chunkable {
    associatedtype SeparatorType
    associatedtype ReturnType

    func chunk (with separator: SeparatorType) -> [ReturnType]
}

extension Chunkable where Self == String {
    func chunk (with separator: Character) -> [String] {
        return self.split(separator: separator).map { String.init($0) }
    }
}

Here is the compiler error:

Same-type constraint type 'String' does not conform to required protocol 'Chunkable'

Obviously, having a "value type" related contraint is causing the issue, but I have a hard time understanding why.

If I add extension String: Chunkable {}

then no more error, the compiler seems to manage to "connect all the dots".

Someone having a good understanding of the Swift compiler may help me understand this ... I'd appreciate it a lot.

Thanks.

The error is exactly right. When you write

you are extending all types that conform to Chunkable where that type is also String.

However, String has not been conformed to Chunkable, so there are no types that fit these constraints. You are being reminded by the compiler to conform String to Chunkable. This is how you do that:

…at which point you might as well just put the extension on String in the first place.

2 Likes

Thanks for your answers.

Let's say I want to build a framework that provides this kind of default behavior ONLY if the user of my framework makes String conform to Chunkable in its application. How can I achieve this ?

Because inside my framework, I don't want to make String conform to Chunkable. Conformance is a choice given to the user of the framework.

Yep it could absolutely be written that way. In fact, I was just trying different ways of writing this ... and was surprised not being able to write it like that.

Users should never conform a type they do not own to a protocol they do not own. This causes numerous problems down the line too involved to enumerate here. Although not banned by the compiler altogether, it is neither an encouraged nor a completely supported use case.

thanks for your insights Xiaodi. I understand your point.

Do you know why it is permitted when the constraint is applied to a Class (where Self: ...) but not to a value type (with same-type constraint) ?

A user can create a subclass that they own, which they can then conform to protocols. There is no problem with conforming a type you do own to a protocol you don’t own, or a type you don’t own to a protocol you do own—in fact, that’s explicitly supported.

Additionally, that syntax was only accidentally supported for many versions of Swift, and full support was only recently enabled. Where it does not forbid non-conforming final or closed classes just like it does for structs, it’s arguably a bug.