Currently, an enum
with no case
s cannot synthesize conformance to Equatable
and Hashable
:
// This does not compile
enum NoCases: Hashable { }
// This does compile:
enum OneCase: Hashable {
case one
}
I would like to change this and I've opened a PR to do so.
The current limitation is artificial. It is possible to have the compiler synthesize the conformance in this case. There's no technical reason why it shouldn't. (If you're wondering what that looks like, please read through the pitch thread for SE-0215).
However, the original proposal to synthesize Hashable and Equatable implementations said this:
The compiler does not synthesize P's requirements for an enum with no cases because it is not possible to create instances of such types.
But the inability to create instance of these types doesn't mean that the conformance isn't helpful or even sometimes necessary. I case that I'm frequently running into is where the type is used to fulfill a type requirement with generics, conditional conformance, or protocols (see code sample at the end of this post).
However, the original proposal does say that the compiler won't do this. What is required from an evolution perspective here? Does this require a separate proposal? Should the original proposal be amended in some way?
// Something approximating The Elm Architecture
// We'd like to constraint `Message` and `Action` to be `Equatable` for
// testing reasons.
protocol Component {
associatedtype Message: Equatable
mutating func update(_: Message) -> Command?
nonmutating func render() -> UI<Message>
}
enum UI<Message: Equatable>: Equatable {
case button(String, Message)
case text(String)
}
struct MyComponent: Component {
// This component doesn't actually send any messages, but it might someday.
// The message has to be `Equatable` because:
// 1. It's required by `Component.Message` (associatedtype requirement)
// 2. It's required by `UI.Message` (generic requirement)
enum Message: Equatable {}
mutating func update(_ message: Message) -> Command? {
switch message { }
}
nonmutating func render() -> UI<Message> {
return UI.text("Hello, World!")
}
}