[Pitch] Hashable types on RawRepresentable enums or a protocol for custom enum-like types


(Adrian Zubarev) #1

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


(Adrian Zubarev) #2

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


(Joe Groff) #3

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 literal type constraint only affects the sugar syntax using the ': String' and 'case X = 1' syntax. If you write an enum's conformance explicitly, you can use any raw type you like:

enum Test: RawRepresentable {
  case something, nothing

  init?(rawValue: A) {
    switch rawValue.value {
    case "something": self = .something
    case "nothing": self = .nothing
    default: return nil
    }
  }

  var rawValue: A {
    switch self {
    case .something: return A(value: "something")
    case .nothing: return A(value: "nothing")
    }
  }
}

though it's up to you at this point to guarantee the 1:1 correspondence between raw values and enum values that RawRepresentable assumes.

-Joe

···

On Oct 3, 2016, at 12:50 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:
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 <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Karl) #4

Enum raw types don't have to be strings/integers, but they have to be expressable by string or integer literals. We don't guarantee uniqueness per se, but we do check for duplicate literals and auto-increment integers to fill gaps.
  
So all you have to do is make your custom type conform to ExpressibleByStringLiteral and you can use it as an enum's raw type.
  
Karl

···

  
On Oct 3, 2016 at 9:50 pm, <Adrian Zubarev via swift-evolution (mailto:swift-evolution@swift.org)> wrote:
  
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 (mailto:swift-evolution@swift.org) https://lists.swift.org/mailman/listinfo/swift-evolution


(Rien) #5

+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


(Karl) #6

Also IIRC, both of these limitations go away if you conform to RawRepresentable yourself.
  
There is no magic to RawRep. The compiler will just synthesise a failable initialiser and 'rawValue' computed property accessor. Both just simple switch statements matching your provided literals and returning the appropriate enum case.
  
Specifically, RawRep does not change the raw representation of the enum. It's always going to be the smaller integer that fits the number of cases.

···

  
On Oct 4, 2016 at 6:56 pm, <Karl Wagner (mailto:razielim@gmail.com)> wrote:
  
Enum raw types don't have to be strings/integers, but they have to be expressable by string or integer literals. We don't guarantee uniqueness per se, but we do check for duplicate literals and auto-increment integers to fill gaps.
  
So all you have to do is make your custom type conform to ExpressibleByStringLiteral and you can use it as an enum's raw type.
  
Karl
  
>
> On Oct 3, 2016 at 9:50 pm, <Adrian Zubarev via swift-evolution (mailto:swift-evolution@swift.org)> wrote:
>
>
>
>
>
> 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 (mailto:swift-evolution@swift.org) https://lists.swift.org/mailman/listinfo/swift-evolution
>
  


(Adrian Zubarev) #7

Doesn’t this imply more performance cost? Don’t get me wrong but the value here is not fixed and computed all over again which might waste resources if the calculation is complicated. Sure we could build some workarounds here and there, but the codebase won’t get any prettier after that.

Another though is that enums just need stored properties to solve the main problem here nicely. I don’t remember what the outcome of that talk was back then. I’ll search for that conversation soon.

Anyways, thank you Joe for showing us the possible workaround.

···

--
Adrian Zubarev
Sent with Airmail

Am 4. Oktober 2016 um 19:52:11, Joe Groff (jgroff@apple.com) schrieb:

On Oct 3, 2016, at 12:50 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

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 literal type constraint only affects the sugar syntax using the ': String' and 'case X = 1' syntax. If you write an enum's conformance explicitly, you can use any raw type you like:

enum Test: RawRepresentable {
case something, nothing

init?(rawValue: A) {
switch rawValue.value {
case "something": self = .something
case "nothing": self = .nothing
default: return nil
}
}

var rawValue: A {
switch self {
case .something: return A(value: "something")
case .nothing: return A(value: "nothing")
}
}
}

though it's up to you at this point to guarantee the 1:1 correspondence between raw values and enum values that RawRepresentable assumes.

-Joe
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


(Adrian Zubarev) #8

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?

···

--
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


(Joe Groff) #9

I doubt it. Formally, integer and string literals are also constructor calls, but they're inlined and constant-folded away in most cases. A struct construction is also likely to be optimized. The code pattern I presented is exactly what the compiler automatically generates when you use the sugar syntax.

-Joe

···

On Oct 4, 2016, at 11:07 AM, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

Doesn’t this imply more performance cost? Don’t get me wrong but the value here is not fixed and computed all over again which might waste resources if the calculation is complicated. Sure we could build some workarounds here and there, but the codebase won’t get any prettier after that.


(Adrian Zubarev) #10

Okay thanks, I’ll keep that in mind.

···

--
Adrian Zubarev
Sent with Airmail

Am 4. Oktober 2016 um 20:16:12, Joe Groff (jgroff@apple.com) schrieb:

On Oct 4, 2016, at 11:07 AM, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

Doesn’t this imply more performance cost? Don’t get me wrong but the value here is not fixed and computed all over again which might waste resources if the calculation is complicated. Sure we could build some workarounds here and there, but the codebase won’t get any prettier after that.

I doubt it. Formally, integer and string literals are also constructor calls, but they're inlined and constant-folded away in most cases. A struct construction is also likely to be optimized. The code pattern I presented is exactly what the compiler automatically generates when you use the sugar syntax.

-Joe


(Ben Rimmington) #11

It can be surprising when enum cases don't behave like `static let` properties:

  Welcome to Apple Swift version 3.0 (swiftlang-800.0.46.2 clang-800.0.38).
    1> import Foundation
    2> enum Test: NSString {
    3. case test
    4. }
    5> Test.test.rawValue === Test.test.rawValue
  $R0: Bool = false

-- Ben

···

On 4 Oct 2016, at 19:16, Joe Groff wrote:

On Oct 4, 2016, at 11:07 AM, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

Doesn’t this imply more performance cost? Don’t get me wrong but the value here is not fixed and computed all over again which might waste resources if the calculation is complicated. Sure we could build some workarounds here and there, but the codebase won’t get any prettier after that.

I doubt it. Formally, integer and string literals are also constructor calls, but they're inlined and constant-folded away in most cases. A struct construction is also likely to be optimized. The code pattern I presented is exactly what the compiler automatically generates when you use the sugar syntax.

-Joe


(Xiaodi Wu) #12

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