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

Vladimir.S svabox at gmail.com
Mon Apr 25 10:31:05 CDT 2016


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)

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


More information about the swift-evolution mailing list