<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">Continuing on this vein, there is another huge reason this proposal is incomplete and won’t solve the problem.<div class=""><br class=""></div><div class="">This proposal, as I outlined previously, is all about binary compatibility and functional resilience in the face of changing libraries. However, it falls woefully short by only considering the binary implications of changing enums.</div><div class=""><br class=""></div><div class="">The problem of binary compatibility extends *far* beyond the mutation of enums between library versions. By only considering the “enum problem”, we are ignoring a much larger and worse problem that will be even easier for libraries to succumb to. It’s easy as a library author to inadvertently rename a method or change the type of a parameter, or add a parameter, or change the return type, or change the implementation semantics, or remove a type, or remove a function, in such a way that a linking app cannot handle. This is why the burden of binary compatibility rightfully rests on library authors, and not app authors.&nbsp;</div><div class=""><br class=""></div><div class="">The thing that changes has the responsibility to maintain compatibility for the thing that hasn’t changed.</div><div class=""><br class=""></div><div class="">We should absolutely not implement this proposal; it only addresses a single portion of a very large problem. Instead, we should figure out what the broader binary compatibility story is. If we can answer *that* and provide the necessary features to address it, then enum resilience will naturally fall out of it. Focusing on the enum problem is focusing on the wrong problem.</div><div class=""><br class=""></div><div class="">Dave<br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Dec 21, 2017, at 11:02 AM, Dave DeLong &lt;<a href="mailto:swift@davedelong.com" class="">swift@davedelong.com</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; line-break: after-white-space;" class="">I realized further why we should not implement this proposal: It forces the problem of binary compatibility on the app developer, when experience has shown us that problem is better handled by the libraries.<div class=""><br class=""></div><div class=""><b class="">Binary Compatibility</b></div><div class=""><br class=""></div><div class="">“Binary compatibility” is the notion that, even if the libraries you link against change, your app will still behave as it did when it was first compiled. For Swift apps these days, we don’t really have this problem, *yet*. We do have the problem of “binary compatibility” with Apple-provided frameworks, but those are all written in Objective-C, and so the question of “Swift” binary compatibility is still up-in-the-air.</div><div class=""><br class=""></div><div class="">Post-ABI stability, we still won’t have much issue with swift binary compatibility on Apple platforms, because there isn’t a mechanism to ship a framework to your users independently of an app update. So from the app POV, none of this will be a problem for Apple platform developers.</div><div class=""><br class=""></div><div class="">It will be a problem for non-Apple platform developers. As a simple example, let’s say I write a web app in Swift, and deploy it to a server that has some built-in Swift-on-the-server libraries. Here, my Swift app is decoupled from the libraries, and either one can update independently of each other. If the server owner decides to update from Swift 6 to Swift 6.1, that’s cool. But my web app should continue to run and behave *as if* the server were still running Swift 6, because it has not been re-compiled to use Swift 6.1 features.</div><div class=""><br class=""></div><div class="">This is the situation today on Apple platforms. Every app deployed to an Apple device includes a little piece of information in the executable file indicating which SDK was used to compile the app. At runtime, the system frameworks read this value and then alter their behavior accordingly. This is why apps written against the iOS 9 SDK continue to work on iOS 11 devices; UIKit and friends are altering their behavior to provide iOS 9 semantics.&nbsp;</div><div class=""><br class=""></div><div class="">This is “binary compatibility”: the binary (your app) continues to be compatible with the dynamically linked frameworks present on the system, even though those frameworks may change.</div><div class=""><br class=""></div><div class="">When you have a setup where the frameworks do NOT provide binary compatibility, you end up in DLL Hell [1]. This is the same frustrating scenario when you’re in when you’re doing stuff with homebrew and find that this package you want has multiple dependencies, but these dependencies want different versions of the same library. [2]</div><div class=""><br class=""></div><div class=""><b class="">Exhaustive Enums</b></div><div class=""><b class=""><br class=""></b></div><div class="">All of the discussion around exhaustive enums has been from the point-of-view of “what should the behavior be when the libraries change”. Thinking back, I’m actually surprised this is a question at all, because Apple answered this *years* ago: THE BEHAVIOR SHOULD REMAIN UNCHANGED. It is up to the library authors to ensure that they’re doing what the compiled-and-unchanging application is expecting them to do.</div><div class=""><br class=""></div><div class="">This discussion around exhaustive enums is basically saying “can we force the developers to deal with binary incompatibility?”. We absolutely should not. There are far more app developers than library developers, and it would be a massively wasteful expenditure of engineering effort to force each and every app developer to deal with binary incompatibility, when the library can do it for them. That is the entire *purpose* of having libraries: abstract out a problem so that I, as an app developer, don’t have to spend the effort to do it myself.</div><div class=""><br class=""></div><div class=""><b class="">Where We Should Go</b></div><div class=""><b class=""><br class=""></b></div><div class="">Instead of forcing developers to deal with incompatible libraries, we should be discussing ways to make binary compatibility easier to implement in libraries.</div><div class=""><br class=""></div><div class="">One of the major problems I struggled with as a UIKit engineer was the presence of huge numbers of “if … else” checks in the code to deal with binary compatibility. It exploded the cyclomatic complexity of the classes and was a major source of technical debt that I struggled to not add to.</div><div class=""><br class=""></div><div class="">I would love to see some sort of formal API versioning that we could do instead in libraries, along with easy runtime support for checking the linked version of libraries, making it easy to strategize implementations based on version, etc.</div><div class=""><br class=""></div><div class="">But forcing developers to deal with binary incompatibility is a solution we’ve long known to be a bad one. We should not perpetuate that sin in Swift.</div><div class=""><br class=""></div><div class="">Dave</div><div class=""><br class=""></div><div class="">[1]:&nbsp;<a href="https://en.wikipedia.org/wiki/DLL_Hell" class="">https://en.wikipedia.org/wiki/DLL_Hell</a></div><div class="">[2]:&nbsp;<a href="https://en.wikipedia.org/wiki/Dependency_hell" class="">https://en.wikipedia.org/wiki/Dependency_hell</a></div><div class=""><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Dec 20, 2017, at 10:23 AM, Dave DeLong 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; line-break: after-white-space;" class=""><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Dec 19, 2017, at 3:58 PM, Ted Kremenek 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=us-ascii" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><p style="-webkit-print-color-adjust: exact; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255); margin-top: 0px !important;" class="">The review of "SE 0192 - Non-Exhaustive Enums" begins now and runs through&nbsp;<strong style="-webkit-print-color-adjust: exact;" class="">January 3, 2018</strong>.</p><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);" class="">The proposal is available here:</p><blockquote style="-webkit-print-color-adjust: exact; margin: 15px 0px; border-left-width: 4px; border-left-style: solid; border-left-color: rgb(221, 221, 221); padding: 0px 15px; color: rgb(119, 119, 119); font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);" class=""><div style="-webkit-print-color-adjust: exact; margin: 0px;" class=""><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md</a></div></blockquote><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);" class="">When reviewing a proposal, here are some questions to consider:</p><ul style="-webkit-print-color-adjust: exact; margin: 15px 0px; padding-left: 30px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);" class=""><li style="-webkit-print-color-adjust: exact; margin: 0px;" class=""><p style="-webkit-print-color-adjust: exact; margin: 0px 0px 15px;" class="">What is your evaluation of the proposal?</p></li></ul></div></div></blockquote>A very strong -1. I do not believe this is the appropriate solution to the problem.</div><div class=""><br class=""></div><div class="">• While the goal of the proposal is to ensure the correctness of *client* code, it does nothing to enforce the correctness of evolving *library* code. As a library author, I can declare a public enum as “exhaustive”, yet still add a new case in the next release. Nothing in the proposal prevents me from doing this, yet doing so would obviously break any clients of my library.&nbsp;</div><div class=""><br class=""></div><div class="">• The name “exhaustive” is misleading for uninformed library authors. An author creates an enum and then thinks “is that all of the cases? Yep! OK, it’s @exhaustive”. Then the next evolution of the library occurs, new cases arise, and now the enum isn’t exhaustive to handle the new cases. So a case gets added, and the formerly-but-not-actually-exhaustive enum is re-stamped as exhaustive, because it once again handles all known cases. “Exhaustive” is not a strong enough name. It does not contain the idea of eternal permanence. Once an enum gets branded as exhaustive and shipped as such, *it can never change*. “Exhaustive” does not imply that, and the lack of that implication will confuse library authors.</div><div class=""><br class=""></div><div class="">• This proposal does not address the case of “publicly exhaustive enums with private cases”. Consider NSExpression.ExpressionType: when creating NSPredicates from format strings, it is easy to create sub-expressions whose expression types are not one of the publicly listed cases. Based on the proposal, NSExpression.ExpressionType would be correctly imported as a non-exhaustive enum. HOWEVER. There is nothing *stopping* a library author from declaring a publicly exhaustive enum (like NSExpression.ExpressionType), but having private cases that get leaked (accidentally or not) past the public barrier and end up in client code. This proposal does nothing to prevent that.</div><div class=""><br class=""></div><div class="">The summary of these objections is this: you fundamentally cannot trust libraries that are not bundled with your application to not change in unexpected ways. Or in other words, if you don’t have the source code, you cannot trust it. And even if you do have the source code, it’s still questionable once you start bridging things in from other languages where this sort of safety is not enforced.</div><div class=""><br class=""></div><div class="">To summarize the summary: Leaving a judgement of “exhaustive or not” up to fallible library authors isn’t safe.</div><div class=""><br class=""></div><div class="">To summarize the summary of the summary: people are a problem.</div><div class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><ul style="-webkit-print-color-adjust: exact; margin: 15px 0px; padding-left: 30px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);" class=""><li style="-webkit-print-color-adjust: exact; margin: 0px;" class=""><p style="-webkit-print-color-adjust: exact; margin: 0px 0px 15px;" class="">Is the problem being addressed significant enough to warrant a change to Swift?</p></li></ul></div></div></blockquote>Yes, the problem is significant, but in my opinion this is the wrong answer.<br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><ul style="-webkit-print-color-adjust: exact; margin: 15px 0px; padding-left: 30px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);" class=""><li style="-webkit-print-color-adjust: exact; margin: 0px;" class=""><p style="-webkit-print-color-adjust: exact; margin: 0px 0px 15px;" class="">Does this proposal fit well with the feel and direction of Swift?</p></li></ul></div></div></blockquote><div class="">No. Implementing this proposal would give the appearance of safety while still leaving developers subtly but dangerously vulnerable to imperfectly written libraries (ie, all of them).</div><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><ul style="-webkit-print-color-adjust: exact; margin: 15px 0px; padding-left: 30px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);" class=""><li style="-webkit-print-color-adjust: exact; margin: 0px;" class=""><p style="-webkit-print-color-adjust: exact; margin: 0px 0px 15px;" class="">How much effort did you put into your review? A glance, a quick reading, or an in-depth study?</p></li></ul></div></div></blockquote><div class="">I’ve been following the email threads, and I’ve spent years as a library author, both on Apple frameworks and my own personal libraries.</div><div class=""><br class=""></div><div class="">Dave</div></div></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div></div></div></blockquote></div><br class=""></div></body></html>