[swift-evolution] PITCH: New :== operator for generic constraints

Charles Srstka cocoadev at charlessoft.com
Tue Aug 16 22:52:08 CDT 2016


> On Aug 16, 2016, at 8:51 PM, Slava Pestov <spestov at apple.com> wrote:
> 
> Here is why we must have that requirement. Consider the following code:
> 
> protocol P {
>   init()
> }
> 
> struct A : P {
>   init() {}
> }
> 
> struct B : P {
>   init() {}
> }
> 
> func makeIt<T : P>() -> T {
>   return T()
> }
> 
> I can use this function as follows:
> 
> let a: A = makeIt() // Creates a new ‘A'
> let a: B = makeIt() // Creates a new ‘B’
> 
> Now suppose we allow P to self-conform. Then the following becomes valid:
> 
> let p: P = makeIt()
> 
> What exactly would makeIt() do in this case? There’s no concrete type passed in, or any way of getting one, so there’s nothing to construct. The same issue would come up with static methods here.

Argh, that’s particularly frustrating since in something like ‘func foo<T : P>(t: T)’ or ‘func foo<S : Sequence>(s: S) where S.IteratorElement: P’, you’re only ever getting instances anyway since the parameter is in the input, so calling initializers or static functions isn’t something you can even do (unless you call .dynamicType, at which point you *do* have a concrete type at runtime thanks to the dynamic check).

I wish there were a way to have partial conformance in cases like these. Like how this causes what’s probably Swift’s most confusing compiler error (certainly one of its most asked about):

protocol P: Equatable {
    static func ==(l: Self, r: Self) -> Bool
    
    func foo()
}

struct S: P {
    static func ==(l: S, r: S) -> Bool {
        return true
    }
    
    func foo() {
        print("foo")
    }
}

let s = S()
let p = s as P // error: Protocol ‘P’ can only be used as a generic constraint because it has Self or associated type requirements

It would make using protocols so much less teeth-grinding if the compiler *did* allow you to type the variable as P, but then would just throw an error if you tried to call one of the “problem” methods (in this case, using the ‘==' operator would be an error, but calling ‘foo’ would be fine). If this were possible, the conformance for a variable typed P would just not pick up “illegal” things like initializers, and would also leave out conformance for things like 'makeIt()' above which return the generic parameter in the output, rather than the input, necessitating a concrete type. I’m probably dreaming, I know.

Actually, what I wish is that Swift had an equivalent of the 'id <P>’ type in Objective-C. That notation always stood for an instance of something that conformed to P, rather than "maybe P itself, and maybe something that conforms to it”. If we could do that, we could just pass sequences of 'id <P>’ (in whatever syntax we gave it in Swift) to a sequence where Element: P, and it’d work fine regardless of anything that prevented P from conforming to P.

Charles

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160816/a683b147/attachment.html>


More information about the swift-evolution mailing list