[swift-evolution] ValueEnumerable protocol with derived implementation for enums

Jacob Bandes-Storch jtbandes at gmail.com
Tue May 24 01:37:37 CDT 2016

...1 month passes...

On Mon, Apr 25, 2016 at 8:31 AM, Vladimir.S via swift-evolution <
swift-evolution at swift.org> wrote:

> Sorry, if was discussed earlier, tried to find in conversations in this
> thread but didn't find:
> Could someone please briefly describe why "community is in agreement" -
> "The "allValues" behavior should be provided by conformance to some
> protocol" ?
> I mean, what is purpose of the protocol? What else, other than allValues
> for enums, could be implemented with such protocol? How it will be
> used?(Like to see a possible code sample)

Whether the `allValues` property should be exposed as a protocol
requirement was one of the main questions I brought up at the beginning of
this thread.

Personally, I'm fine with ValuesEnumerable being a "magic protocol" like
ErrorProtocol, because the most important use case is being able to write
e.g. `NSTextAlignment.allValues` with a compiler-provided implementation. A
proper associatedtype declaration can come later, once generics are mature

> How I think about this feature: we have "simple" enums(.First, .Second,
> .Third), we have enums with "raw" values(.First = 1) and we have "complex"
> enums like
> enum E<T> {
>     case First(Int,T)
>     case Second(SomeStruct)
> }
> What we need? We need to be able to iterate over all declared cases in
> enum. Often we needs to pre-create some resources depending on what 'kind'
> of values(and their count) could be in enum.
> Let's take this "complex" E<T> enum.
> IMO we need to be able to have such code:
> let columns = Columns(count: E<Int>.allValues.count)
> for e in E<Int>.allValues {
>   switch e { // << here is a problem for complex enums, it can't return
> actial enum value as assotiated values are not known (Int,T)/SomeStruct
> // but there is no problem for "simple" enums to return actual value here
>     case .First : columns.newColumn(titled: "First", color: red)
>     case .Second : columns.newColumn(titled: "Second", color: blue)
>     // !!! no 'default:' here : this will protect us if E is changed
>   }
> }
> As I understand, to be able to iterate 'complex' enums we need some new
> type related to enum. I mean what exactly are ".First" and ".Second" that
> are specified inside 'switch'? I.e. what is placed by compiler inside
> 'switch' as ".First" and as ".Second"? What hidden property of e is
> compared with these ".First" and ".Second" ?
> Here is the code:
> var e : E<String> = .First(1, "str")
> switch e { // e is compared in run-time
>     case .First : print("first")   // e is a concrete value of 'complex'
> enum, but we can compare just '.First' about it. So, .First does not create
> an instance of E<String>, it is some 'special' value
>     case .Second : print("second")
> }
> It seems like we need some 'magic' EnumCase type and some compiler changes
> to be able to write some kind of this:
> for e in E<Int>.allCases { // e is EnumCase, we have need .allCases
>   switch e {
> // here compiler allows to use our EnumCase to get a general 'kind' of
> defined cases in enum
> // i.e. 'e' contains the same value(and only this value) that compiler
> internally stores in 'switch' now (in code above)
>     case .First : columns.newColumn(titled: "First", color: red)
>     case .Second : columns.newColumn(titled: "Second", color: blue)
>     // !!! no 'default' here, it is important!
>     // because of this we need compiler magic insted of checking some
>     // function like E<Int>.caseIf(from: .First) as function will require
>     // a 'default:' clause.
>   }
> }
> As for 'simple' enums - they can be iterated without such special
> 'EnumCase' type, but for consistency probably could be implemented in the
> same way. Or for 'complex' enums we need such a special case.
> As for ordering, it is clear for me that we need order items in allValues
> exactly as defined in code. We always can have rawValue from enum, but
> can't get enum definition order by rawValue.
> Opinions?
> Please let me know if something is incorrect in my reasoning

Your reasoning is correct. This proposal was only intended to handle the
"simple" case, because having a good solution for the simple case sooner,
rather than waiting for a *perfect* solution much later, seems like a good
idea to me.

To me, it seems that a "magic protocol" with no public requirements,
producing an internal (non-resilient) static array, is a reasonable
solution that *might* be able to fit into the Swift 3 timeframe, and I
think that'd be a huge boon to language users. I also don't think it
precludes further improvements.

Do others agree? Disagree? Is it definitely out of scope for Swift 3
regardless of the approach we choose?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160523/cf8ad024/attachment.html>

More information about the swift-evolution mailing list