[swift-evolution] [Completing Generics] Private and multiple conformances

Douglas Gregor dgregor at apple.com
Thu Mar 3 00:10:32 CST 2016


> On Mar 2, 2016, at 9:42 PM, Joe Groff <jgroff at apple.com> wrote:
> 
>> 
>> On Mar 2, 2016, at 9:32 PM, Douglas Gregor <dgregor at apple.com <mailto:dgregor at apple.com>> wrote:
>> 
>>> 
>>> On Mar 2, 2016, at 9:12 PM, Joe Groff <jgroff at apple.com <mailto:jgroff at apple.com>> wrote:
>>> 
>>>> 
>>>> On Mar 2, 2016, at 8:26 PM, Douglas Gregor <dgregor at apple.com <mailto:dgregor at apple.com>> wrote:
>>>> 
>>>> 
>>>>> On Mar 2, 2016, at 5:38 PM, Joe Groff <jgroff at apple.com <mailto:jgroff at apple.com>> wrote:
>>>>> 
>>>>> 
>>>>>> On Mar 2, 2016, at 5:22 PM, Douglas Gregor via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>>>> 
>>>>>> Private conformances 
>>>>>> 
>>>>>> Right now, a protocol conformance can be no less visible than the minimum of the conforming type’s access and the protocol’s access. Therefore, a public type conforming to a public protocol must provide the conformance publicly. One could imagine removing that restriction, so that one could introduce a private conformance:
>>>>>> 
>>>>>> public protocol P { }
>>>>>> public struct X { }
>>>>>> extension X : internal P { … } // X conforms to P, but only within this module
>>>>>> 
>>>>>> The main problem with private conformances is the interaction with dynamic casting. If I have this code:
>>>>>> 
>>>>>> func foo(value: Any) {
>>>>>>   if let x = value as? P { print(“P”) }
>>>>>> }
>>>>>> 
>>>>>> foo(X())
>>>>>> 
>>>>>> Under what circumstances should it print “P”? If foo() is defined within the same module as the conformance of X to P? If the call is defined within the same module as the conformance of X to P? Never? Either of the first two answers requires significant complications in the dynamic casting infrastructure to take into account the module in which a particular dynamic cast occurred (the first option) or where an existential was formed (the second option), while the third answer breaks the link between the static and dynamic type systems—none of which is an acceptable result.
>>>>> 
>>>>> You don't need private conformances to introduce these coherence problems with dynamic casting. You only need two modules that independently extend a common type to conform to a common protocol. As Jordan discussed in his resilience manifesto, a publicly-subclassable base class that adopts a new protocol has the potential to create a conflicting conformance with external subclasses that may have already adopted that protocol. 
>>>> 
>>>> Right, multiple conformances do happen in our current model. Personally, I think that the occurrence of multiple conformances should effectively be an error at runtime unless the conformances are effectively identical (same type witnesses with the same conformances may be a reasonable approximation), and even then it’s worthy of a diagnostic as early as we can produce one, because the amount of infrastructure one needs to handle multiple conformances is significant.
>>> 
>>> If it's a runtime error, that's a huge resilience liability, since any library adding a conformance would potentially be causing its users to start crashing at load time.
>> 
>> My hope is that we could limit the failure mode to the case where the conflicting conformances are different in a way that affects soundness, e.g., different type witnesses for the same associated type.
> 
> I don't think we can reliably tell. As currently implemented, we generate a fresh set of witness thunks for every conformance, so the function pointers in the two modules' conformances would look different to the runtime.

I was thinking we only “have” to compare the type witnesses and any conformances they carry with them, because that’s what we need to ensure type soundness.

>> I certainly agree that we’re creating both a resilience liability and a liability when composing libraries (the author of library E below did nothing wrong, but observes weird behavior), but the alternatives seem so much worse.
> 
> The only place I can see where we rely on coherence is in the runtime, as you've mentioned. We're pretty good about statically maintaining conformance identity through the stack, so we ought to be able to catch static conformance mismatches in types and maybe even give reasonable error messages. It wouldn't be hard for the runtime to notice when it has a key collision in its conformance table and log a warning either—that would be consistent with what the ObjC runtime does with class or category collisions between images.

Right. My concern is that, in the case where we’ve lost soundness, we need to trap to avoid introducing undefined behavior. Perhaps I’m worrying overmuch.

	- Doug

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


More information about the swift-evolution mailing list