[swift-evolution] Working with enums by name

Paul Cantrell cantrell at pobox.com
Wed Jun 1 13:53:07 CDT 2016


Indeed, you’re quite right: verified that I get “Mars” even when the enum is in a framework.

It took a little digging to get back what I was thinking of: it’s when the enum value is inside some other data structure that you get an annoyingly fully qualified name:

    enum CoinSide {
        case heads
        case tails
    }

    enum CoinState {
        case inAir
        case landed(showing: CoinSide)
    }

    print(CoinState.inAir)  // → "inAir"

    // …but…

    print(CoinState.landed(showing: .heads))  // → "landed(CoinSide.heads)"

    print([CoinSide.heads: 1])  // → "[CoinSide.heads: 1]"

This is the case I was thinking of where the module name comes into play. Drop those enums into a framework, and you’ll get "landed(MyFramework.CoinSide.heads)". Ugh!

So what if you want those second two to print out as "landed(heads)" and "[heads: 1]”? This does not work:

    enum CoinSide: CustomStringConvertible {
        case heads
        case tails
        
        var description: String {
            return String(self) // infinite recursion
        }
    }

There’s no automatically implemented description (or debugDescription) property we can delegate to. The conversion of .heads →  "heads" is apparently runtime magic that we lose access to as soon as we implement CustomStringConvertible or CustomDebugStringConvertible, and therefore AFAIK there's no way to do this other than switching on all the cases:

    enum CoinSide: CustomStringConvertible {
        case heads
        case tails
        
        var description: String {
            switch(self) {
                case heads: return "heads"
                case tails: return "tails"
            }
        }
    }

Is is true that there’s no better way? Is there some CustomVerboseDebugStringConvertible protocol we can override to change only the "MyFramework.CoinSide.heads" form?

If indeed there is no better way, it seems like a really good case for having the synthesized .caseName property. Even if there is a CustomVerboseDebugStringConvertible to override in the particular case above, being able to customize an enum’s description but still use the enum case name in that description seems like a compelling use case as well.

Cheers, P

> On Jun 1, 2016, at 10:47 AM, Leonardo Pessoa <me at lmpessoa.com> wrote:
> 
> Paul, in all my tests for this thread printing the enum value only
> produced the enum value's name ("Mars" in your example). The proposal
> of having a .caseName (or should it better be .caseValue to cover
> enums with associated values? any other suggestions?) will prevent
> that changes to this behaviour crash apps in the future as this should
> always produce the same result even if the string representation
> changes.
> 
> L
> 
> On 1 June 2016 at 12:15, Paul Cantrell via swift-evolution
> <swift-evolution at swift.org> wrote:
>> IIRC, string interpolation prepends the module name if the enum belongs to a module: “MyLib.Mars” instead of just “Mars”. It’s also been a source of compiler crashes, at least in the past.
>> 
>> Those two factors forced me into this ugliness: https://github.com/bustoutsolutions/siesta/blob/master/Source/ResourceObserver.swift#L106-L115
>> 
>> A clean, documented, supported way of exposing the enum case name that the runtime clearly already has available seems sensible — and should be independent of the raw type.
>> 
>> Cheers, P
>> 
>>> On Jun 1, 2016, at 5:10 AM, Charlie Monroe via swift-evolution <swift-evolution at swift.org> wrote:
>>> 
>>> This is, however, kind of a hack IMHO that relies on the compiler behavior that isn't well documented.
>>> 
>>> For example, this:
>>> 
>>> enum Planet {
>>>      case Earth
>>>      case Mars
>>> }
>>> 
>>> "\(Planet.Mars)" // This is "Mars"
>>> 
>>> 
>>> Works as well. You don't need to have the represented value to be String.
>>> 
>>> Note that this:
>>> 
>>> - works both when you have a plain enum, or enum Planet: Int, or whatever raw value kind
>>> - does not work (!) when declared as @objc - then the result is "Planet".
>>> 
>>>> On Jun 1, 2016, at 9:52 AM, Patrick Smith via swift-evolution <swift-evolution at swift.org> wrote:
>>>> 
>>>> I had no idea you could do this!!
>>>> 
>>>>> On 1 Jun 2016, at 12:32 PM, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
>>>>> 
>>>>> Who said anything about repeating the name?
>>>>> 
>>>>> Welcome to Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.30). Type :help for assistance.
>>>>> 1> enum Planet: String { case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune }
>>>>> 2> Planet.mercury.rawValue
>>>>> $R0: String = "mercury"
>>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160601/8bdc3cc6/attachment.html>


More information about the swift-evolution mailing list