There are still a lot of open questions here to solve.
- How to statically guarantee the uniqueness + immutability of the
hashValues?
-
Should we allow only the usage of an initializer?
-
Sometimes an init might be not enough and you’d wish you can use
custom function which would return the same value for the same input you
provide.
struct A : Hashable { … }
enum B : A {
case a: A(someLabel: someInput)
case b: createAFunction()
case c: createA(with: someOtherInput)
}
-
Should we allow only value types here or how do we handle reference
types?
A protocol to create custom enum-like types would be really interesting
and useful. Instead of switch checking the value that conforms to that
new protocol directly I’d suggest that we need some kind of an interface to
satisfy and enable the enum-like switch usage (or maybe I’m totally wrong
here).
protocol SomeFancyName : RawRepresentable {
var interface: SomeType { get }
}
struct C : SomeFancyName { /* implement */ }
let c = C.someCase
switch c.interface {
case .someCase:
// Handle
case .someOtherCase:
// Handle
// No need for `default` when all cases are present
}
I couldn’t think up a simple and elegant model for such a protocol. Any
suggestions is welcome.
-
Does the core team and the community feel this might have some
potential future?
-
Does this impact the ABI somehow?
A protocol wouldn't work, I don't think, because classes can be extended
and so exhaustiveness can't be guaranteed, and there is no syntax to limit
protocols only to structs and final classes.
While I've sometimes wished RawRepresentable could be used with more
Hashable types, for your motivating problem, you can already get pretty
close to your desired end goal:
protocol _RawRepresentable : RawRepresentable { }
extension _RawRepresentable where RawValue : Hashable {
static func ~= (lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue == rhs.rawValue
}
}
struct Example : _RawRepresentable {
let rawValue: String
init?(rawValue: String) {
switch rawValue {
case "foo", "bar":
self.rawValue = rawValue
default:
return nil
}
}
static let foo = Example(rawValue: "foo")!
static let bar = Example(rawValue: "bar")!
}
let ex = Example.foo
switch ex {
case Example.foo: // the syntax could be made more intelligent here to
allow `.foo`
print("Foo!")
case Example.bar:
print("Bar!")
default:
fatalError()
}
As in the other thread, I don't understand your unwillingness to writing a
default case. It is a very practical solution, and it tells your reader
that your custom type is really meant to be switched over exhaustively. In
fact, it does so at the point of use much more clearly than a protocol
conformance that would not be nearly as obvious to the reader of the code.
···
On Tue, Oct 4, 2016 at 2:07 AM, Adrian Zubarev via swift-evolution < swift-evolution@swift.org> wrote:
--
Adrian Zubarev
Sent with Airmail
Am 4. Oktober 2016 um 08:25:24, Rien (rien@balancingrock.nl) schrieb:
+1.
I have several cases where I cannot use enums, this proposal would solve
that.
> On 03 Oct 2016, at 21:53, Adrian Zubarev via swift-evolution < > swift-evolution@swift.org> wrote:
>
> I made a typo in my previous post.
>
> Bikeshdding with correct types:
>
> struct A : Hashable { /* implement everything */ }
>
> // Variant 1:
> enum Test : A {
> case something = A(value: "something")
> case nothing = A(value: "nothing")
> }
>
> // Variant 2:
>
> protocol SomeFancyName : RawRepresentable { … }
>
> struct Test : SomeFancyName {
>
> let rawValue: A
> init?(rawValue: A) {
> // Implement + reject unwanted `A`s
> }
>
> static let something = Test(rawValue: A(value: "something"))
> static let nothing = Test(rawValue: A(value: "nothing"))
> }
>
> let value = Test.something
>
> switch value {
>
> case .something:
> // handle
>
> case .nothing:
> // handle
>
> // Because of `SomeFancyName` the switch can use enum-like pattern
matching + does not need the `default` case when all cases are present
> }
>
>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 3. Oktober 2016 um 21:50:07, Adrian Zubarev (
adrian.zubarev@devandartist.com) schrieb:
>
>> Hi there,
>>
>> I’m interested if this idea has some potential future in Swift or not.
>>
>> Currently RawRepresentable enums accept only a subset of literal types
like String, Character and the Integer family (enum Name : String { … }).
>>
>> Sometimes this is not enough for my use-case and I wish I could feed my
enums with other Hashable types!
>>
>> As a workaround I can create a custom struct or even a class and
conform it to RawRepresentable and fake an enum with some static variables
(similar to what is done with OptionSet types).
>>
>> The problem there is that I cannot use the same switch pattern matching
like with enums. I’d wish either enums could accept Hashable types (maybe
with some restriction) or the existence on a protocol to build custom
enum-like types with strucs/classes and use the same switch pattern
matching.
>>
>> struct A : Hashable { /* implement everything */ }
>>
>> // Variant 1:
>> enum Test : A {
>> case something = A(rawValue: A(value: "something"))
>> case nothing = A(rawValue: A(value: "nothing"))
>> }
>>
>> // Variant 2:
>>
>> protocol SomeFancyName : RawRepresentable { … }
>>
>> struct Test : SomeFancyName {
>>
>> let rawValue: A
>> init?(rawValue: A) {
>> // Implement + reject unwanted `A`s
>> }
>>
>> static let something = A(rawValue: A(value: "something"))
>> static let nothing = A(rawValue: A(value: "nothing"))
>> }
>>
>> let value = Test.something
>>
>> switch value {
>>
>> case .something:
>> // handle
>>
>> case .nothing:
>> // handle
>>
>> // Because of `SomeFancyName` the switch can use enum-like pattern
matching + does not need the `default` case when all cases are present
>> }
>>
>>
>>
>> --
>> Adrian Zubarev
>> Sent with Airmail
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution