<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><div style="direction: inherit;"><br></div><br>Sent from my iPhone</div><div><br>On Aug 4, 2016, at 2:36 AM, Haravikk via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br><br></div><blockquote type="cite"><div><span></span><br><blockquote type="cite"><span>On 4 Aug 2016, at 03:19, Brent Royal-Gordon via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><blockquote type="cite"><span>On Aug 3, 2016, at 10:17 AM, Manav Gabhawala via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>I was wondering why this would put any more of a burden on the runtime</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>than simple inheritance of protocols. The way this could be</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>implemented is to augment the ConformanceTable for nominal types by</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>looking up its protocol extension’s inheritance clauses. I can</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>definitely see this impacting compile time but I don’t see why runtime</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>performance will be any different than simple inheritance. Further,</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>cyclic chains can be detected and broken (compiler error) during the</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>second pass of semantic analysis.</span><br></blockquote></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>My understanding—which may be incorrect, by the way—is that the issue is mainly with protocol extensions adding conformances, not specifically with those conformances being conditional, and that it specifically has to do with `is` and `as?` checks across module boundaries.</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>Suppose you have these declarations in module M:</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span> public protocol AProtocol {…}</span><br></blockquote><blockquote type="cite"><span> public protocol BProtocol: AProtocol {…}</span><br></blockquote><blockquote type="cite"><span> public protocol CProtocol {…}</span><br></blockquote><blockquote type="cite"><span> </span><br></blockquote><blockquote type="cite"><span> // Public or otherwise doesn't matter here.</span><br></blockquote><blockquote type="cite"><span> public struct Foo: BProtocol {…}</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>Foo essentially has a flat list of the protocols it conforms to attached to it. Notionally, you can think of that list as looking like:</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span> Foo.self.conformsTo = [BProtocol.self, AProtocol.self]</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>And when you write `foo is CProtocol`, that eventually translates into:</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span> foo.dynamicType.conformsTo.contains(CProtocol.self)</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>For a `Foo`, since the `conformsTo` list doesn't include `CProtocol.self`, it returns `false`.</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>Now imagine that you write a new module, N, and in it you say:</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span> extension Foo: CProtocol {…}</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>You have now retroactively conformed `Foo` to `CProtocol`. Swift needs to reach into module M and add `CProtocol.self` to the `Foo.self.conformsTo` list. This is perfectly doable for a concrete type—it's one flat list, after all.</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>Instead, though, imagine that module N extended `AProtocol` to add a conformance:</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span> extension AProtocol: CProtocol {…}</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>There are two ways to handle this. One is to find all types conforming to `AProtocol`, recursively, and add `CProtocol.self` to their conformance list. The other is to scrap the flat list of conformances and instead make `is` and `as?` recursively search each protocol. Either way, you have replaced a fast, flat operation with a slow, recursive one.</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>Conditional conformance adds another wrinkle to this, of course—you must not only recursively search the list, but also evaluate the condition to see if it applies in this case. But the general problem of having to replace a fast search with a slow search applies either way.</span><br></blockquote><span></span><br><span>Great explanation! This switch from flat to recursively searched though seems like it would only occur when the extension is in an external module though; for internal modules would it not still be possible to determine the flat list for each type? In that case extending a type from another module could be either disallowed, or produce a warning to indicate the performance implication?</span><br><span></span><br><span>The feature would still be very useful even just for internal use after all. Also it seems useful on a relatively small number of types, and the number of external modules that need/want to do this must narrow that even further, so external extensions may be quite niche, i.e- not worth losing the feature for internal use if that is indeed easier?</span><br></div></blockquote><div style="direction: inherit;"><br></div><div style="direction: inherit;">Swift doesn't really have any features that stop working across modules. We're okay with the programmer having to think more and be more explicit across module boundaries (since it is API design at that point), but it'd take a very strong argument to have different runtime semantics across module boundaries. </div><div style="direction: inherit;"><br></div><div style="direction: inherit;">FWIW, I'm planning to write a complete proposal for conditional conformances and will start posting drafts once it is far enough along to be useful. It won't have support for protocols conforming to other protocols, though. </div><div style="direction: inherit;"><br></div><div style="direction: inherit;"> - Doug</div><div style="direction: inherit;"><br></div><blockquote type="cite"><div><span>_______________________________________________</span><br><span>swift-evolution mailing list</span><br><span><a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a></span><br><span><a href="https://lists.swift.org/mailman/listinfo/swift-evolution">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br></div></blockquote></body></html>