Proposal: Enum 'count' functionality

To be clear, I think there should be a distinction between what would be returned by `cases` and `rawValues`, and I think there is good reason to include both:

- `cases` would return actual instances of the enum type, or the constructor if there is an associated value for the case and an instance can’t be automatically created
- `rawValues` would also exist for enums that have a RawRepresentable value.

The collision of using “case" in something like `for case in SomeEnum.cases` is unfortunate, but I think it’s still the most clear and accurate representation of something that does what I described above. Initially I was thinking there was an existing proposal that would fix this, but now I realize that it’s only scoped to keyword arguments: https://github.com/apple/swift-evolution/blob/master/proposals/0001-keywords-as-argument-labels.md

Joe, thank you for your thoughts on this! Yes I agree that it doesn’t make sense to try to generate a list of all possible values for all associated types — and that’s pretty much my point. Deciding to omit such unsupported cases is one way to deal with that issue, but it seems confusing and limiting to me that some enum cases would not be represented in the array of values, while others are represented multiple times. I’m not saying that there’s no value to something like that and I’m certainly not opposed to the inclusion of that kind of thing, but I’m interested in finding a way to deal with this in a manner that is more understandable, predictable, and flexible.

I’d love to hear what you think about returning an array that includes constructors for the cases with associated values. Here’s what I like about that idea:

- The array consists of a 1-to-1 mapping regardless of the type of case. This is more understandable and predictable in my opinion.
- It provides the ability to cover more use-cases, while I believe the other approach would prevent certain things from being possible in a dynamic way.
- It still allows for developers to generate an array with the recursive structure/Cartesian product as you described.

Here is an example that demonstrates the usefulness of constructors as the included value for cases with associated values. I am providing a stubbed implementation of a `cases` static var. The concept is that you have an enum that defines a number of built-in color schemes, but provides a mechanism for users to dynamically create their own color schemes.

I have a couple other real-world ideas for where this would be useful too.

Downsides I can see to this approach:

- For enums that have disparate constructor signatures, [Any] would have to be the return value of cases, which doesn’t seem ideal because the cases array would always require some kind of manual manipulation to be useful.
- There isn’t currently a way in the type system to know what case you are working based on the constructor. For instance say two cases both have a constructor of (String), you can’t determine which case you are working on until you call the constructor to instantiate the case. This could be done by looking at the index of the constructor in the cases array, but that is brittle and messy. If there was a way to determine that more dynamically, this would be more powerful and easier to use.

···

On Dec 23, 2015, at 6:00 AM, Pierre Monod-Broca via swift-evolution <swift-evolution@swift.org> wrote:

+1 for an ordered collection of all cases, it could be an ordered set to please proponents of a set.

I have no strong opinions about the name
`cases` is good, but I agree it begs to do ''for case in SomeEnum.cases''
`values` is good, and IMO it's consistent with `rawValue` when there is one, not confusing

--
Pierre

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

Zef, do you really think `rawValues` are worth adding?

With `cases`, they would be one `map` away, no?

R+

···

On 23 Dec 2015, at 17:21, Zef Houssney via swift-evolution <swift-evolution@swift.org> wrote:

To be clear, I think there should be a distinction between what would be returned by `cases` and `rawValues`, and I think there is good reason to include both:

- `cases` would return actual instances of the enum type, or the constructor if there is an associated value for the case and an instance can’t be automatically created
- `rawValues` would also exist for enums that have a RawRepresentable value.

The collision of using “case" in something like `for case in SomeEnum.cases` is unfortunate, but I think it’s still the most clear and accurate representation of something that does what I described above. Initially I was thinking there was an existing proposal that would fix this, but now I realize that it’s only scoped to keyword arguments: https://github.com/apple/swift-evolution/blob/master/proposals/0001-keywords-as-argument-labels.md

Joe, thank you for your thoughts on this! Yes I agree that it doesn’t make sense to try to generate a list of all possible values for all associated types — and that’s pretty much my point. Deciding to omit such unsupported cases is one way to deal with that issue, but it seems confusing and limiting to me that some enum cases would not be represented in the array of values, while others are represented multiple times. I’m not saying that there’s no value to something like that and I’m certainly not opposed to the inclusion of that kind of thing, but I’m interested in finding a way to deal with this in a manner that is more understandable, predictable, and flexible.

I’d love to hear what you think about returning an array that includes constructors for the cases with associated values. Here’s what I like about that idea:

- The array consists of a 1-to-1 mapping regardless of the type of case. This is more understandable and predictable in my opinion.
- It provides the ability to cover more use-cases, while I believe the other approach would prevent certain things from being possible in a dynamic way.
- It still allows for developers to generate an array with the recursive structure/Cartesian product as you described.

Here is an example that demonstrates the usefulness of constructors as the included value for cases with associated values. I am providing a stubbed implementation of a `cases` static var. The concept is that you have an enum that defines a number of built-in color schemes, but provides a mechanism for users to dynamically create their own color schemes.

Example of Swift enum with allValues array containing constructors for cases with associated values · GitHub

I have a couple other real-world ideas for where this would be useful too.

Downsides I can see to this approach:

- For enums that have disparate constructor signatures, [Any] would have to be the return value of cases, which doesn’t seem ideal because the cases array would always require some kind of manual manipulation to be useful.
- There isn’t currently a way in the type system to know what case you are working based on the constructor. For instance say two cases both have a constructor of (String), you can’t determine which case you are working on until you call the constructor to instantiate the case. This could be done by looking at the index of the constructor in the cases array, but that is brittle and messy. If there was a way to determine that more dynamically, this would be more powerful and easier to use.

On Dec 23, 2015, at 6:00 AM, Pierre Monod-Broca via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

+1 for an ordered collection of all cases, it could be an ordered set to please proponents of a set.

I have no strong opinions about the name
`cases` is good, but I agree it begs to do ''for case in SomeEnum.cases''
`values` is good, and IMO it's consistent with `rawValue` when there is one, not confusing

--
Pierre

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

+1 for adding `.allCases` to enums. I just wanted to propose this exact idea but then found this thread (and another where the thread starter was pointed to this thread).

The count would then be `MyEnum.allCases.count` and the rawValues would be `MyEnum.allCases.map{ $0.rawValue }`. I think the latter two are sufficient here, no need for extra integration IMO. But those points could be still discussed.

Shouldn’t we create a new properly named proposal for this though? This thread / proposal is about adding the .count and the naming is somehow misleading.

– Cihat

···

Am 23.12.2015 um 23:50 schrieb Rudolf Adamkovič via swift-evolution <swift-evolution@swift.org>:

Zef, do you really think `rawValues` are worth adding?

With `cases`, they would be one `map` away, no?

R+

On 23 Dec 2015, at 17:21, Zef Houssney via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

To be clear, I think there should be a distinction between what would be returned by `cases` and `rawValues`, and I think there is good reason to include both:

- `cases` would return actual instances of the enum type, or the constructor if there is an associated value for the case and an instance can’t be automatically created
- `rawValues` would also exist for enums that have a RawRepresentable value.

The collision of using “case" in something like `for case in SomeEnum.cases` is unfortunate, but I think it’s still the most clear and accurate representation of something that does what I described above. Initially I was thinking there was an existing proposal that would fix this, but now I realize that it’s only scoped to keyword arguments: https://github.com/apple/swift-evolution/blob/master/proposals/0001-keywords-as-argument-labels.md

Joe, thank you for your thoughts on this! Yes I agree that it doesn’t make sense to try to generate a list of all possible values for all associated types — and that’s pretty much my point. Deciding to omit such unsupported cases is one way to deal with that issue, but it seems confusing and limiting to me that some enum cases would not be represented in the array of values, while others are represented multiple times. I’m not saying that there’s no value to something like that and I’m certainly not opposed to the inclusion of that kind of thing, but I’m interested in finding a way to deal with this in a manner that is more understandable, predictable, and flexible.

I’d love to hear what you think about returning an array that includes constructors for the cases with associated values. Here’s what I like about that idea:

- The array consists of a 1-to-1 mapping regardless of the type of case. This is more understandable and predictable in my opinion.
- It provides the ability to cover more use-cases, while I believe the other approach would prevent certain things from being possible in a dynamic way.
- It still allows for developers to generate an array with the recursive structure/Cartesian product as you described.

Here is an example that demonstrates the usefulness of constructors as the included value for cases with associated values. I am providing a stubbed implementation of a `cases` static var. The concept is that you have an enum that defines a number of built-in color schemes, but provides a mechanism for users to dynamically create their own color schemes.

Example of Swift enum with allValues array containing constructors for cases with associated values · GitHub

I have a couple other real-world ideas for where this would be useful too.

Downsides I can see to this approach:

- For enums that have disparate constructor signatures, [Any] would have to be the return value of cases, which doesn’t seem ideal because the cases array would always require some kind of manual manipulation to be useful.
- There isn’t currently a way in the type system to know what case you are working based on the constructor. For instance say two cases both have a constructor of (String), you can’t determine which case you are working on until you call the constructor to instantiate the case. This could be done by looking at the index of the constructor in the cases array, but that is brittle and messy. If there was a way to determine that more dynamically, this would be more powerful and easier to use.

On Dec 23, 2015, at 6:00 AM, Pierre Monod-Broca via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

+1 for an ordered collection of all cases, it could be an ordered set to please proponents of a set.

I have no strong opinions about the name
`cases` is good, but I agree it begs to do ''for case in SomeEnum.cases''
`values` is good, and IMO it's consistent with `rawValue` when there is one, not confusing

--
Pierre

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution