I think library writers sometime have a tendency to downplay the importance of clean declarations. As long as the call site looks clean it's good right? But when something goes wrong people will refer to the declaration, and if the declaration is complex it makes troubleshooting more complex.
With a where clause, to understand how .toggleStyle(.switch) works you have to understand what a conditional declaration with where does, and then you what Self is referring to within a protocol, and then have some imagination to figure out what's the point of having this where in the first place. That's a mouthful of concepts to teach in one go. (Technically you don't have to understand it all, but you have to understand it enough to know you can ignore it.)
I'll bite. I think it's slightly harmful, but I had to think about what I wrote in my last post before realizing that. Let me know if I got something wrong in my examples; I'm extrapolating from what I understood in the proposal.
I find it very surprising that some static properties can be called on the protocol and others can't. Consider this:
protocol P {
static var number { get }
}
struct S: P {
static let number = 1
}
extension P {
static var a: Int { 1 }
static var b: Int { Self.number }
static var c: S { S() }
static let d = S()
}
let x = P.a // error, can't infer Self
let y = P.b // error, can't infer Self
let z = P.c // ok, Self inferred to be return type S
let w = P.d // ok, Self inferred to be return type S
Whether the static member is available on the protocol depends on its return type. I don't think that's very sound. What's actually preventing them from being called is the impossibility to infer a Self.
It's a funny thing is that you can make the x and y line above compile by adding this:
extension Int: P {
var number: Int { 2 }
}
let x = P.a // ok, can infer Self to Int now
let y = P.b // ok, can infer Self to Int now
In practice that means that in contexts where a protocol conformance is visible members will be callable directly on P and in contexts where the conformance is not visible it won't.
And by conforming Int to P, the behaviour of b (which uses Self) becomes a bit surprising:
P.b // returns 2; Self inferred to Int
Int.b // returns 2; Self inferred to Int
S.b // returns 1; Self inferred to S
Here Int becomes the default Self when called on P simply because it's the return type, but the returned value varies depending on Self and makes little sense when called on the protocol itself. Think this is a far fetched scenario?
FixedWidthInteger.bitWidth // Self inferred to Int
That's the only concrete example I could find, but there might be others.
What would be a better rule for calling things on a protocol is that they don't use Self at all. We're only introducing this strange inference of Self because there's no syntax to make the declaration not require a Self. But I think a @notUsingSelf attribute would be better for that than the proposed inference of based on the return type.