Help with "protocol FooBar where Self: Bar"

I have come across some code similar to this:

protocol Bar {
}

protocol FooBar where Self: Bar {
    var key: Int { get }
}

I don't quite understand this.

The second protocol declaration seems to be saying a conforming type must also conform to Bar, but the following code compiles even though Foo doesn't conform to Bar.

struct Foo: FooBar {
    let key: Int
}

let bar : Bar = Foo (key: 7)
print (bar)

I am almost tempted to say these two declarations are equivalent:

protocol FooBar: Bar {
    var key: Int { get }
}

protocol FooBar where Self: Bar {
    var key: Int { get }
}

Is this just a superficial difference, or is there something more profound?

2 Likes

My understanding is that protocol FooBar where Self: Bar is equivalent to protocol FooBar: Bar, meaning that writing struct Foo: FooBar also conforms Foo to Bar. You can see this in action if you add a requirement to Bar:

protocol Bar {
	var id: Int { get }
}

protocol FooBar where Self: Bar {
    var key: Int { get }
}

struct Foo: FooBar {
    let key: Int
}
// error: type 'Foo' does not conform to protocol 'Bar'
// note: protocol requires property 'id' with type 'Int'
1 Like

It seems to me that this represents a language-wide consistency offering two redundant forms. Personally, I quite dislike the way that the standard library code uses the latter form. But if that's what we need in order to have where clauses at all, okey dokey. :upside_down_face:

func ƒ<T: Protocol>(_: T) { }
func ƒ<T>(_: T) where T: Protocol { }

struct S<T: Protocol> { }
struct S<T> where T: Protocol { }