List all values of a simple enum and extension constraint to enum types


(Trevör Anne Denise) #1

Hello everyone,

As I was writing a program, I realised that I could make it safer by being able to list all possible cases of a Swift enum.
This is similar to what has been described there:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001233.html

Is there any updates about it since 2015?

Also, do you think this would be a good idea to make extensions constrainable by enum types, like that?
extension Type where P1: enum {
}

You could then write something similar to this:

protocol A {
associatedtype P1
associatedtype P2
static var p1PossibleValues:[P1] { get }
static var p2PossibleValues:[P2] { get }
}

extension A where P1: enum, P2: enum {
  static var p1PossibleValues:[P1] { return p1PossibleValues.allValues }
  static var p2PossibleValues:[P2] { return p2PossibleValues.allValues }
}

Would it make sense to do it this way?

Trevör


(David Sweeris) #2

Almost… You could have the compiler generate that for 2/3 of the types of enum, but it can’t do anything with enums that have associated values. I wrote a bit of software a while back that does as much as I could figure out how to do automatically, then makes in a compile-time error to not fill-in the blanks (which is still annoying, but at least you don’t find out about your mistake when your program crashes). Feel free to do whatever you want with it: https://github.com/TheOtherDave/EnumEnhancer

Hope that helps
- Dave Sweeris

···

On Mar 10, 2017, at 10:15 AM, Trevör ANNE DENISE via swift-evolution <swift-evolution@swift.org> wrote:

Hello everyone,

As I was writing a program, I realised that I could make it safer by being able to list all possible cases of a Swift enum.
This is similar to what has been described there:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001233.html

Is there any updates about it since 2015?

Also, do you think this would be a good idea to make extensions constrainable by enum types, like that?
extension Type where P1: enum {
}

You could then write something similar to this:

protocol A {
associatedtype P1
associatedtype P2
static var p1PossibleValues:[P1] { get }
static var p2PossibleValues:[P2] { get }
}

extension A where P1: enum, P2: enum {
  static var p1PossibleValues:[P1] { return p1PossibleValues.allValues }
  static var p2PossibleValues:[P2] { return p2PossibleValues.allValues }
}

Would it make sense to do it this way?


(Robert Widmann) #3

This feature keeps being brought up. SR-3050 <https://bugs.swift.org/browse/SR-3050> and rdar://problem/28952398 <rdar://problem/28952398> are tracking it, as well as this Evolution proposal by Jacob <https://github.com/apple/swift-evolution/pull/114>. The implementation has been discussed multiple times on social media (one example that comes to mind <https://twitter.com/jtbandes/status/834633693138350080>). At this point it’s just a matter of sitting down to flesh out the implementation and seeing its consequences on Swift code, which we now have ample time to do because this feature is not in scope for Swift 4.

~Robert Widmann

···

On Mar 10, 2017, at 1:15 PM, Trevör ANNE DENISE via swift-evolution <swift-evolution@swift.org> wrote:

Hello everyone,

As I was writing a program, I realised that I could make it safer by being able to list all possible cases of a Swift enum.
This is similar to what has been described there:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001233.html

Is there any updates about it since 2015?

Also, do you think this would be a good idea to make extensions constrainable by enum types, like that?
extension Type where P1: enum {
}

You could then write something similar to this:

protocol A {
associatedtype P1
associatedtype P2
static var p1PossibleValues:[P1] { get }
static var p2PossibleValues:[P2] { get }
}

extension A where P1: enum, P2: enum {
  static var p1PossibleValues:[P1] { return p1PossibleValues.allValues }
  static var p2PossibleValues:[P2] { return p2PossibleValues.allValues }
}

Would it make sense to do it this way?

Trevör
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Tony Allevato) #4

I think having a static collection of enum values for enums where no cases
have associated values is a totally reasonable thing to do, and I think
omitting this on enums with associated values is also completely
reasonable. In a sense, those two kinds of enums serve different purposes:
the former usually describe a finite set of discrete *fixed* values, where
a collection of them makes sense; the latter is more often an infinite
(theoretically) or at least finite and large collection of *parameterized*
values where a preëxisting set can't or shouldn't be known.

Rather than constrain against "enum", which I think would be problematic
because of those differences among enums, I think a good way to do this
would be to model it with a protocol and have the compiler synthesize it
when possible. For example, imagine this protocol, which I'll give a really
terrible and contrived name because I can't think of a good one currently:

protocol HasOnlyAFixedSetOfPossibleValues {
  static var allValues: [Self] { get }
}

then the compiler could synthesize it such that the given definition:

enum Foo { case bar, baz, quux }

actually becomes

enum Foo: HasOnlyAFixedSetOfPossibleValues \{
&nbsp;&nbsp;case bar, baz, quux
&nbsp;&nbsp;static var allValues: \[Foo\] \{ return \[\.bar, \.baz, \.quux\] \}
\}
\`\`\`

Then, you can get the behavior you want by constraining against
HasOnlyAFixedSetOfPossibleValues, which is more in line with how you would
use similar protocols like RawRepresentable\. It also means you could have
non\-enum types conform to it and use them in the same contexts, if it made
sense to do so\.

Of course, there are a bunch more questions to be addressed, like what type
allValues should be, should it be lazy, should it be ordered, etc\., but
making it protocol\-driven feels like it would best fit in the language\. The
basic building blocks are already there; you just need to define the
protocol and have the compiler generate its implementation like the others
that it already does\.

<details class='elided'>
<summary title='Show trimmed content'>&#183;&#183;&#183;</summary>

On Mon, Mar 13, 2017 at 4:43 PM David Sweeris via swift\-evolution &lt; swift\-evolution@swift\.org&gt; wrote:

> On Mar 10, 2017, at 10:15 AM, Trevör ANNE DENISE via swift\-evolution &lt; &gt; swift\-evolution@swift\.org&gt; wrote:
>
> Hello everyone,
>
> As I was writing a program, I realised that I could make it safer by being
> able to list all possible cases of a Swift enum\.
> This is similar to what has been described there:
>
> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001233.html
>
> Is there any updates about it since 2015?
>
> Also, do you think this would be a good idea to make extensions
> constrainable by enum types, like that?
> extension Type where P1: enum \{
> \}
>
> You could then write something similar to this:
>
> protocol A \{
> associatedtype P1
> associatedtype P2
> static var p1PossibleValues:\[P1\] \{ get \}
> static var p2PossibleValues:\[P2\] \{ get \}
> \}
>
> extension A where P1: enum, P2: enum \{
> static var p1PossibleValues:\[P1\] \{ return p1PossibleValues\.allValues \}
> static var p2PossibleValues:\[P2\] \{ return p2PossibleValues\.allValues \}
> \}
>
> Would it make sense to do it this way?
>
> Almost… You could have the compiler generate that for 2/3 of the types of
> enum, but it can’t do anything with enums that have associated values\. I
> wrote a bit of software a while back that does as much as I could figure
> out how to do automatically, then makes in a compile\-time error to not
> fill\-in the blanks \(which is still annoying, but at least you don’t find
> out about your mistake when your program crashes\)\. Feel free to do whatever
> you want with it: https://github.com/TheOtherDave/EnumEnhancer
>
> Hope that helps
> \- Dave Sweeris
> \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
> swift\-evolution mailing list
> swift\-evolution@swift\.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

</details>

(Xiaodi Wu) #5

See: https://github.com/apple/swift-evolution/pull/114
According to that discussion, the core team has decided that this is out of
scope for Swift 4 stage 2.

···

On Mon, Mar 13, 2017 at 7:44 PM, Tony Allevato via swift-evolution < swift-evolution@swift.org> wrote:

I think having a static collection of enum values for enums where no cases
have associated values is a totally reasonable thing to do, and I think
omitting this on enums with associated values is also completely
reasonable. In a sense, those two kinds of enums serve different purposes:
the former usually describe a finite set of discrete *fixed* values, where
a collection of them makes sense; the latter is more often an infinite
(theoretically) or at least finite and large collection of *parameterized*
values where a preëxisting set can't or shouldn't be known.

Rather than constrain against "enum", which I think would be problematic
because of those differences among enums, I think a good way to do this
would be to model it with a protocol and have the compiler synthesize it
when possible. For example, imagine this protocol, which I'll give a really
terrible and contrived name because I can't think of a good one currently:

protocol HasOnlyAFixedSetOfPossibleValues {
  static var allValues: [Self] { get }
}

then the compiler could synthesize it such that the given definition:

enum Foo { case bar, baz, quux }

actually becomes

enum Foo: HasOnlyAFixedSetOfPossibleValues \{
&nbsp;&nbsp;case bar, baz, quux
&nbsp;&nbsp;static var allValues: \[Foo\] \{ return \[\.bar, \.baz, \.quux\] \}
\}
\`\`\`

Then, you can get the behavior you want by constraining against
HasOnlyAFixedSetOfPossibleValues, which is more in line with how you
would use similar protocols like RawRepresentable\. It also means you could
have non\-enum types conform to it and use them in the same contexts, if it
made sense to do so\.

Of course, there are a bunch more questions to be addressed, like what
type allValues should be, should it be lazy, should it be ordered, etc\.,
but making it protocol\-driven feels like it would best fit in the language\.
The basic building blocks are already there; you just need to define the
protocol and have the compiler generate its implementation like the others
that it already does\.

On Mon, Mar 13, 2017 at 4:43 PM David Sweeris via swift\-evolution &lt; &gt; swift\-evolution@swift\.org&gt; wrote:

> On Mar 10, 2017, at 10:15 AM, Trevör ANNE DENISE via swift\-evolution &lt; &gt;&gt; swift\-evolution@swift\.org&gt; wrote:
>
> Hello everyone,
>
> As I was writing a program, I realised that I could make it safer by
> being able to list all possible cases of a Swift enum\.
> This is similar to what has been described there:
> https://lists.swift.org/pipermail/swift-evolution/
> Week\-of\-Mon\-20151207/001233\.html
>
> Is there any updates about it since 2015?
>
> Also, do you think this would be a good idea to make extensions
> constrainable by enum types, like that?
> extension Type where P1: enum \{
> \}
>
> You could then write something similar to this:
>
> protocol A \{
> associatedtype P1
> associatedtype P2
> static var p1PossibleValues:\[P1\] \{ get \}
> static var p2PossibleValues:\[P2\] \{ get \}
> \}
>
> extension A where P1: enum, P2: enum \{
> static var p1PossibleValues:\[P1\] \{ return p1PossibleValues\.allValues \}
> static var p2PossibleValues:\[P2\] \{ return p2PossibleValues\.allValues \}
> \}
>
> Would it make sense to do it this way?
>
> Almost… You could have the compiler generate that for 2/3 of the types of
> enum, but it can’t do anything with enums that have associated values\. I
> wrote a bit of software a while back that does as much as I could figure
> out how to do automatically, then makes in a compile\-time error to not
> fill\-in the blanks \(which is still annoying, but at least you don’t find
> out about your mistake when your program crashes\)\. Feel free to do whatever
> you want with it: https://github.com/TheOtherDave/EnumEnhancer
>
> Hope that helps
> \- Dave Sweeris
> \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
> 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