> On 3. Jan 2018, at 18:49, Dave DeLong via swift-evolution 
> <swift-evolution@swift.org> wrote:
>> On Jan 3, 2018, at 10:36 AM, Matthew Johnson <matt...@anandabits.com 
>> <mailto:matt...@anandabits.com>> wrote:
>>> On Jan 3, 2018, at 11:07 AM, Dave DeLong via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> IMO this is still too large of a hammer for this problem.
>>> This whole “unexpected case” thing is only a problem when you’re linking 
>>> libraries that are external to/shipped independently of your app. Right 
>>> now, the *only* case where this might exist is Swift on the server. We 
>>> *might* run in to this in the future once the ABI stabilizes and we have 
>>> the Swift libraries shipping as part of iOS/macOS/Linux. Other than this, 
>>> unexpected enum cases won’t really be a problem developers have to deal 
>>> with.
>>> Because this will be such a relatively rare problem, I feel like a syntax 
>>> change like what’s being proposed is a too-massive hammer for such a small 
>>> nail.
>>> What feels far more appropriate is:
>>> 🅰️ Teaching the compiler/checker/whatever about the linking semantics of 
>>> modules. For modules that are packaged inside the final built product, 
>>> there is no need to deal with any unexpected cases, because we already have 
>>> the exhaustiveness check appropriate for that scenario (regardless of 
>>> whether the module is shipped as a binary or compiled from source). The app 
>>> author decides when to update their dependencies, and updating those 
>>> dependencies will produce new warnings/errors as the compiler notices new 
>>> or deprecated cases. This is the current state of things and is completely 
>>> orthogonal to the entire discussion.
>> John McCall sketched out a vision of what a solution to this might look like 
>> here: 
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20171218/042333.html
>> <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20171218/042333.html>.
>>> and
>>> 🅱️ Adding an attribute (@frozen, @tangled, @moana, @whatever) that can be 
>>> used to decorate an enum declaration. This attribute would only need to be 
>>> consulted on enums where the compiler can determine that the module will 
>>> *not* be part of the final built product. (Ie, it’s an “external” module, 
>>> in my nomenclature). This, then, is a module that can update independently 
>>> of the final app, and therefore there are two possible cases:
>>>     1️⃣ If the enum is decorated with @frozen, then I, as an app author, 
>>> have the assurance that the enum case will not change in future releases of 
>>> the library, and I can safely switch on all known cases and not have to 
>>> provide a default case. 
>>>     2️⃣ If the enum is NOT decorated with @frozen, then I, as an app 
>>> author, have to account for the possibility that the module may update from 
>>> underneath my app, and I have to handle an unknown case. This is simple: 
>>> the compiler should require me to add a “default:” case to my switch 
>>> statement. This warning is produced IFF: the enum is coming from an 
>>> external module, and the enum is not decorated with @frozen.
>> This does not help people who need to write a switch statement over an enum 
>> vended by a module that ships with the OS keep their code up to date as the 
>> module adds new cases. I find the example of `SKPaymentTransactionState` 
>> provided by Brent Royal-Gordon here: 
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170904/039512.html
>> <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170904/039512.html>
>>  to be compelling.  There are rare but legitimate reasons to switch over all 
>> known cases of a non-@frozen enum that ship with the OS.  These use cases 
>> deserve proper language support.  I think Jordan’s solution strikes a good 
>> balance.
> I disagree that more is needed. In the case of the transaction state, it 
> should not be marked as @moana, and so the compiler would force you to add a 
> “default” case to your switch statements. The switch statements would still 
> be exhaustive with all known cases (if you choose to handle all known cases), 
> but you’d still need a default case because there might be new transaction 
> states in the future.
> In those cases, your app could decide what to do, if that’s possible at all. 
> Maybe there’s other transaction information you could introspect to determine 
> if it succeeded or is still pending or whatever, and then your app could 
> respond as you see fit.
> Dave
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
So here’s something that I’m confused about - you said before that when the 
library updates, the application behaviour should remain the same. Then why is 
it up to the App developers to try and develop forwards-compatible logic 
instead of the library developers to ensure backwards-compatibility?

SKPaymentTransactionState is a great example - it’s exactly what this proposal 
is about. We are all looking at the superficial side of keeping App code 
compiling, when really we should be thinking about the semantics that those 
enums represent. Enums usually mean state, and it’s often difficult to design 
good state-machines which can deal with completely unpredictable values popping 
up. Most of the the time, your default handler is just garbage which you expect 
and hope never gets called IRL.

I’m not convinced that it is possible to write a good default handler for 
SKPaymentTransactionState, or really most enums. If there were other properties 
you could inspect to perform your App logic, you should clearly prefer those 
since they are more robust than an enum which may give you unpredictable values 
in the future. How would users even know about this recommended practice of 
ignoring the enum and looking for ad-hoc state properties? Again, getting this 
stuff right requires careful design and documentation from the library 
developers, regardless if enums are exhaustive or not.

I think the StoreKit library authors got it wrong there; they added a new enum 
case which required special handling; that’s an API-breaking change. They 
should have defined backwards-compatibility behaviour (if that was possible), 
or disabled the feature for Apps which didn’t support it. Just throwing out 
values which you know the App doesn’t understand puts you in dangerous 
territory, even if it doesn’t necessarily crash.

- Karl

swift-evolution mailing list

Reply via email to