<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi Joe,<div class=""><br class=""></div><div class="">Can you compare the developer experience with/without this feature, e.g. paint some scenarios and describe what one would have to do to deal with it?</div><div class=""><br class=""></div><div class="">Thanks,</div><div class="">Dave</div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 31, 2015, at 11:13 AM, Joe Groff via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">A lot of the discussion around the final/sealed-by-default issue focused on the ability in ObjC to extend frameworks or fix bugs in unforeseen ways. Framework developers aren't perfect, and being able to patch a broken framework method can be the difference between shipping and not. On the other hand, these patches become compatibility liabilities for libraries, which have to contend not only with preserving their own designed interface but all the undesigned interactions with shipping apps based on those libraries. The Objective-C model of monkey-patchable-everything has problems, but so does the buttoned-down everything-is-static C++ world many of us rightly fear. However, with the work we're putting into Swift for resilience and strong versioning support, I think we're in a good position to try to find a reasonable compromise. I'd like to sketch out a rough idea of how that might look. Public interfaces fundamentally correspond to one or more dynamic library symbols; the same resilience that lets a new framework version interact with older apps gives us an opportunity to patch resilient interfaces at process load time. We could embrace this by allowing applications to provide `@patch` implementations overriding imported non-fragile public APIs at specific versions:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">import Foundation</div><div class=""><br class=""></div><div class="">extension NSFoo {</div><div class="">&nbsp; @patch(OSX 10.22, iOS 17)</div><div class="">&nbsp; func foo() { ... }</div><div class="">}</div><div class=""><br class=""></div></blockquote>By tying the patch to a specific framework version, we lessen the compatibility liability for the framework; it's clear that, in most cases, the app developer is responsible for testing their app with new framework versions to see if their patch is still needed with each new version. Of course, that's not always possible—If the framework developer determines during compatibility testing that their new version breaks a must-not-break app, and they aren't able to adopt a fix on their end for whatever reason (it breaks other apps, or the app's patch is flawed), the framework could declare that their new version accepts patches for other framework versions too:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">// in Foundation, OSX 10.23</div><div class="">public class NSFoo {</div><div class="">&nbsp; // Compatibility: AwesomeApp patched the 10.22 version of NSFoo.foo.</div><div class="">&nbsp; // However, RadicalApp and BodaciousApp rely on the unpatched 10.22 behavior, so</div><div class="">&nbsp; // we can't change it.</div><div class="">&nbsp; @accepts_patch_from(AwesomeApp, OSX 10.22)</div><div class="">&nbsp; public func foo() { ... }</div><div class="">}</div><div class=""><br class=""></div></blockquote>A sufficiently smart dynamic linker could perhaps resolve these patches at process load time (and probably summarily reject patches for dylibs loaded dynamically with dlopen), avoiding some of the security issues with arbitrary runtime patching. For public entry points to be effectively patchable, we'd have to also avoid any interprocedural optimization of the implementations within the originating module, so there is a performance cost to allowing this patching by default. Sufficiently mature (or arrogant) interfaces could perhaps declare themselves "unpatchable" to admit IPO within their own module. (Note that 'fragile' interfaces which admit cross-module inlining would inherently be unpatchable, and those are likely to be the most performance-sensitive interfaces to begin with.)<div class=""><br class=""></div><div class="">-Joe</div>
<img src="https://u2002410.ct.sendgrid.net/wf/open?upn=JfMPa-2F7wwZPzsZ3QKA8NjtONIYX4SjbWuUxtpfsTY2hzGWYrL3RYDK3CZ9JGpUOyNoHjvSjuNEyibNHnN7jnoJZeOBaaJi8hfwRiOG57-2BAeIS7fLXhAhqjFjU-2FeBhKqESBHtAXTWRXvDZdtYXMhM8LBYulrw2pOZllU27bOYnhYLvmMhnxOYfwL0HVmwbTRabVaKC32x7V-2FmazJseb3Eg3y2vHB3pdnmJ9nUHoYJFvE-3D" alt="" width="1" height="1" border="0" style="height:1px !important;width:1px !important;border-width:0 !important;margin-top:0 !important;margin-bottom:0 !important;margin-right:0 !important;margin-left:0 !important;padding-top:0 !important;padding-bottom:0 !important;padding-right:0 !important;padding-left:0 !important;" class="">
</div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""><div class="">
-Dave
</div>
<br class=""></div></body></html>