The last time I was in this situation, I resolved it by having a shadow enum with the same cases but without any associated value.
I also created shadow enums for error enums. The shadow enum wouldn't have any associated value, and Int as RawValue, and I would also use it as an error code when converting to NSError. But it's not really fun to maintain. Pierre > Le 18 janv. 2017 à 05:51, Andy Chou via swift-evolution > <[email protected]> a écrit : > > I see your point about conformances. In my example, AuthenticationResponse > isn't a generic type, so the conformances spec won't apply. > > I'll go out on a limb and say that 80%+ of the use cases for equality will be > to distinguish enum cases, not the associated values. > > I do like your proposal though. In the thread talking about it someone > mentioned a 'derived' keyword to specify conformance and derivation > simultaneously. I like the idea of being able to say: > > enum AuthenticationResponse: derived Equatable { ... } > > Still, even with derived conformance, it can still be very useful to be able > to test against specific enum cases when the associated values aren't > Equatable. Maybe this example would make it clearer: > > ``` > enum OpaqueResponse { > case success(OpaqueResult) > case failure > } > ``` > > If OpaqueResult is from a library module and its implementation uses private > variables, it may not be easy to make it conform to Equatable. Yet, it would > be nice to be able to say: > > ``` > let result: OpaqueResponse = request() > if request == .failure { ... } > ``` > > A more realistic example comes from the world of Rx, where the original issue > I have came from: > > ``` > let result: Observable<OpaqueResponse> = request() > > result.filter { $0 == .failure } ... > result.filter { $0 == .success } ... > > // The best we can do today looks more like: > result.filter { if case .failure = $0 { return true} else { return false } } > result.filter { $0.isFailure } // but we have to define isFailure ourselves > > // There's a similar issue with assertions > if case .failure = result { assert(false) } > assert({ if case .failure = result { return true } else { return false } }()) > ``` > > I agree it's less of an issue with test cases. The issue arises when we want > a Bool valued expression... > > Andy > >> On Jan 17, 2017, at 6:38 PM, Tony Allevato <[email protected]> wrote: >> >> Conditional conformances doesn't solve enum equality though, because there >> likely won't be a way to utter "enum Foo : Equatable where <all types across >> all associated value payloads are Equatable>" with the generics syntax >> that's available, and conformance alone wouldn't be able to derive the >> implementation. It'll require some work on the compiler's part to generate >> the right implementation—I mentioned a draft proposal I wrote a while back >> for auto-equality of enums and structs where all the components are >> equatable >> <https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad> in >> another thread, but as Robert mentioned, the missing piece is how users opt >> in/out of it. >> >> If you just want to check the case of an enum in a test, what about this? >> >> enum Foo { >> case bar >> case baz(Int) >> } >> let foo = Foo.baz(5) >> guard case .baz = foo else { XCTFail("expected baz"); return } >> >> The "return" being required isn't ideal because XCTFail doesn't return >> Never, but other than that it's not *horrible*. You can do whatever pattern >> matching you need to use or ignore associated values as part of your >> comparison. >> >> >>> On Tue, Jan 17, 2017 at 5:59 PM Andy Chou via swift-evolution >>> <[email protected]> wrote: >>> Yes, here's a reference to the conditional conformance proposal which was >>> accepted: >>> >>> https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md >>> >>> But as I mention in my post, there are cases it doesn't handle. >>> Specifically, when the associated types for an enum aren't equatable >>> themselves, it's still possible to define equality on the enum cases >>> without associated values. >>> >>> Andy >>> >>>> On Jan 17, 2017, at 5:45 PM, Robert Widmann <[email protected]> >>>> wrote: >>>> >>>> Automatic “equatability” of aggregates that contain equatable members has >>>> been discussed on this list quite a few times. (I think I had a branch at >>>> one point that was exploring this kind of deriving mechanism… It seems to >>>> be lost to the sands of time). Everybody seems to agree that it’s a >>>> worthwhile feature, but there needs to be thought put into how it is >>>> exposed to the end user. e.g. Should we continue with silently >>>> implementing these protocols if we can, or should there be some kind of >>>> annotation to tell the compiler to only synthesize what the user wants? >>>> >>>>> On Jan 17, 2017, at 7:15 PM, Andy Chou via swift-evolution >>>>> <[email protected]> wrote: >>>>> >>>>> Enums with associated values can be very useful in Swift, but once you >>>>> add associated values you lose some properties, especially equality: >>>>> >>>>> ``` >>>>> enum AuthenticationResponse { >>>>> case success >>>>> case alert(Alert) >>>>> case reauthenticate >>>>> } >>>>> ``` >>>>> >>>>> Testing for a specific case requires a switch statement or the if pattern >>>>> match syntax: >>>>> >>>>> if case .success = response { … } >>>>> >>>>> But while this works well for control flow, it doesn’t work well for >>>>> cases where we want a Bool, such as assert(). There are also common >>>>> situations with lists and libraries like RxSwift where a filtering >>>>> function uses a Bool valued closure. In these situations the best we can >>>>> do is write functions like: >>>>> >>>>> ``` >>>>> enum AuthenticationResponse { >>>>> case success >>>>> case alert(Alert) >>>>> case reauthenticate >>>>> >>>>> var isSuccess: Bool { >>>>> if case .success = self { >>>>> return true >>>>> } else { >>>>> return false >>>>> } >>>>> } >>>>> >>>>> var isReauthenticate: Bool { >>>>> if case .reauthenticate = self { >>>>> return true >>>>> } else { >>>>> return false >>>>> } >>>>> } >>>>> >>>>> var isAlert: Bool { >>>>> if case .alert(_) = self { >>>>> return true >>>>> } else { >>>>> return false >>>>> } >>>>> } >>>>> } >>>>> ``` >>>>> Any suggestions better than writing out each of these functions >>>>> explicitly? >>>>> >>>>> The conditional conformances proposal coming in Swift 4 solves some of >>>>> this issue, but not completely. If Alert isn’t Equatable, it is still >>>>> useful to test whether the result is .success. For example: >>>>> >>>>> assert(response == .success) >>>>> >>>>> This is perfectly intelligible and I would argue that equality should be >>>>> defined for enums with associated values omitted: >>>>> >>>>> assert(response == .alert) >>>>> >>>>> Here we are ignoring the associated values, and merely checking if the >>>>> enum case is the same. >>>>> >>>>> Andy >>>>> >>>>> _______________________________________________ >>>>> swift-evolution mailing list >>>>> [email protected] >>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>> >>> >>> _______________________________________________ >>> swift-evolution mailing list >>> [email protected] >>> https://lists.swift.org/mailman/listinfo/swift-evolution > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
