[swift-evolution] ValueEnumerable protocol with derived implementation for enums
Vladimir.S
svabox at gmail.com
Tue May 24 16:16:07 CDT 2016
> 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
> enough.
OK. Agree.
> 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.
Support this opinion. We can introduce such a protocol now in 3.0 and
implementation for 'simple' enums and then (3.x or 4) extent it to
'complex' enums.
Btw, I also think we need some .next/.prev properties for cases(i.e. var
emotion = Emotions.sad; emotion = emotion.next // will be '.neutral', then
`.happy`). As even with `.allValues` you need to write a code to find
current case in that array, then return next case. But probably this could
be introduced later.
On 24.05.2016 9:37, Jacob Bandes-Storch wrote:
> ...1 month passes...
>
> On Mon, Apr 25, 2016 at 8:31 AM, Vladimir.S via swift-evolution
> <swift-evolution at swift.org <mailto: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
> enough.
>
>
> 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?
More information about the swift-evolution
mailing list