[swift-evolution] Enums and Source Compatibility

Andrew Bennett cacoyi at gmail.com
Thu Dec 21 16:47:37 CST 2017

Can you go into more detail about why the core team didn't like this?

public enum HomeworkExcuse {
  case eatenByPet
  case thoughtItWasDueNextWeek
  default // NEW}

To me this is very close to an ideal solution, it fixes ABI concerns, it
has sensible defaults. If it was changed a little bit:

public enum HomeworkExcuse {
  case eatenByPet
  case thoughtItWasDueNextWeek
  fallback unknown // NEW}

Then I believe you would be able to have an exhaustive switch like this:

switch thing {
  case eatenByPet: break
  case thoughtItWasDueNextWeek: break
  case unknown: break}

Which would *still allow compile-time errors if new cases are introduced*,
while providing a concise way to show something is not exhaustible.

This would also *support existing enums with "unknown" equivalent cases*
would be able to explicitly label those fields as fallback without needing
to make large code changes.

I see no reason why you shouldn't be able to use ".unknown", which *should
still allow this to be testable*.


On Tue, Oct 3, 2017 at 8:10 AM, Jordan Rose via swift-evolution <
swift-evolution at swift.org> wrote:

> I don't think I have anything to say on this topic that I haven't already
> said:
> - Switching exhaustively over non-exhaustive enums is uncommon.
> - It's more important for a library to build without errors when its
> dependencies change than it is to get an error. (This doesn't apply to
> warnings, though.)
> - Untestable code is dangerous, so having a language feature inherently
> for untestable code seems bad.
> None of that negates your points; it just affects the weighting of whether
> or not 'future' or 'switch!' is worth it. However, I've added a link to
> your email in the proposal proper so that the Core Team and wider review
> audience have a chance to decide differently.
> Jordan
> On Oct 2, 2017, at 08:25, Vladimir.S via swift-evolution <
> swift-evolution at swift.org> wrote:
> Sorry to bother, but I still can't understand how the proposed change
> *without* a 'future' case in switch will change our life and what would be
> our steps to support our code and to not make our code buggy.
> If I misunderstand something - sorry, please point me on this and I hope
> this also help some one like me to understand the subject better.
> For example. I use OAuth2 framework, built by Carthage. Did add the
> OAuth2.framework to my project.
> Currently OAuth2 exports 'public enum OAuth2Error'. I do have a place in
> my code where I switch on each case of such error instance to do my best
> with error: generate detailed description for user, other additional steps
> depending on error.
> Will/should author of OAuth2 make OAuth2Error 'exhaustive' ? No.
> Will new cases be added to that enum in future: Most likely Yes.
> Do I need to switch on each case in my code? Yes.
> Can I currently rely on compiler to keep my error processing in sync with
> error cases defined in framework? Yes.
> Can new cases appear in *run-time* of my app: NO, framework in embedded.
> Will I be able to rely on compiler after the proposed change? No?!
> What should I do to keep my switch in sync with OAuth2Error cases after
> each update of OAuth2 library(framework)? Manually check if new cases are
> added?! Configure lint/other tools to help me with this?!
> What I, as a developer, as a consumer of framework, need - is a way to
> exhaustively switch on *some* external non-exhaustive enums *at the moment
> of compilation*. And we can accomplish this only(AFAICT) with 'future' case
> in 'switch'.
> In case we'll have 'future' case my life will not be *worse* for this
> project : I'll add it to my switch and still can receive help from compiler
> to keep switch exhaustive.
> I don't support the opinion that we can't introduce 'future' case because
> of we can't test it:
> 1. Not being able to keep my switch exhaustive when I need this, and so
> not being able to provide users of my app with best experience - IMO is
> worse.
> 2. In my particular example, 'future' case will be *never* called, if I
> understand correctly.
> 3. If switch on non-exhaustive enum is exhaustive by fact, we can't test
> the 'default' branch also. So, 'future' is in same position here with
> 'default'
> 4. I believe if we'll decide we need 'future' case - we can suggest a way
> to call code in that case during the test process.
> Seems like for embedded frameworks we should apply the same
> rules(regarding enums) as for sources, as we compile the app with concrete
> binary of framework and there just can't be new cases in enums. No?
> Thank you for your time.
> Vladimir.
> On 01.10.2017 3:00, Slava Pestov via swift-evolution wrote:
> On Sep 30, 2017, at 4:46 PM, Karl Wagner via swift-evolution <
> swift-evolution at swift.org <mailto:swift-evolution at swift.org
> <swift-evolution at swift.org>>> wrote:
> I don’t see how it’s impractical. Quite a lot about how the library should
> be optimally compiled and used depends on what you plan to do with it. If
> it’s going to be installed somewhere private and you can guarantee clients
> will always have the latest version, you can assume all data types are
> final, @_fixed_layout, @exhaustive, whatever (essentially in-module). An
> example of that would be a library embedded inside an iOS app bundle. If
> it’s going to be installed somewhere public and expose some API (like
> Apple’s frameworks), then you’re going to have to think about binary
> compatibility.
> That also means that in-app libraries are optimised as much as they can
> be, and that resilience-related changes on the declaration side can be
> limited to the limited set of Swift developers who truly have to care about
> that.
> We do plan on exposing an -enable-resilience flag which basically does
> what you describe. When a library is built without -enable-resilience, all
> types are assumed to be fixed layout, etc. However, we don’t want language
> flags to change language semantics, so exhaustive/nonexhaustive still make
> sense even when building without resilience, I think. When you switch over
> a non-exhaustive enum that came from a library built without
> -enable-resilience, the compiler can still use the most efficient possible
> access pattern and assume that no new cases will be introduced, but the
> type checker would still require a default case to be present. The
> optimizer can then basically strip out the default case as dead code.
> Slava
> - Karl
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20171222/a9fe903d/attachment.html>

More information about the swift-evolution mailing list