-1

Start with an enum in Swift:

enum UnitCode:UInt {
    case Unknown = 0
    case Hz = 1
    case GPM = 2
    case M3_Hour = 3
    case mA = 4
    case PSI = 5
    case Bar = 6
}

For most of those, an expression like:

let text = "\(aUnitCode)"

will produce a nice result, since the printed form matches the code form (e.g. .Hz == "Hz").

But for the M3_Hour, I'd like to print that as m³/hr. So conform to CustomStringConvertable, right? I figured the following would not work:

extension UnitCode: CustomStringConvertible {
    var description:String {
        return self == .M3_Hour ? "m³/hr" : String(describing: self)
    }
}

It did not. Infinite recursion. Thought so. But Swift often surprises me (in both good and bad ways).

If the enum were a super/sub type relationship, I'd call the "super" version of description to get the "default" text rendering of the enum. But I'm not sure how to get the "default stringification of an enum" in my false branch, so that I can tune it for just the one distinct value. Is there a way to do this?

Travis Griggs
  • 21,522
  • 19
  • 91
  • 167
  • 6
    You will just have to write a switch that covers all cases. Sorry, just bite the bullet. – matt Jun 02 '21 at 21:57
  • Thanks @matt. So no way to access/call/send the "base" enum-conversion-to-string machinery basically? – Travis Griggs Jun 02 '21 at 22:24
  • And yet, if don't do *anything* it does the stringification work for me somehow. With no CustomStringConvertible extension, it's still smart enough to turn "\(UnitCode.Hz)" into just "Hz". Somehow, that happens. In this case, it's 99% of what I want. :D – Travis Griggs Jun 02 '21 at 22:38
  • 1
    Downvote because of the utilization of incorrect casing in order to generate better strings with no extra effort. Not a valuable question with only one of them (`mA`) having a good string representation coming from how they should be capitalized in code. –  Jun 03 '21 at 00:19
  • @Jessy - The question is broader than the quibbles of how to express in code a constant that does have a "proper" way of spelling it. It's not my fault that a "Hz" is the correct way to express Hz and that different languages have "conventions" about all enum values that contravene these. The real question was where is the code that does the default enum stringification? Maybe I wanted to call it. – Travis Griggs Jun 03 '21 at 18:20
  • 2
    A simple answer is that the "default enum stringification" is basically a debugging tool and you can't rely on its functionality remaining constant between updates. – EmilioPelaez Jun 03 '21 at 19:02

3 Answers3

2

I think the problem with your actual code is your use of String(describing:) in a CustomStringConvertible implementation. If we ignore CustomStringConvertible and just write a custom property, you can do this sort of thing:

enum UnitCode: UInt {
    case Unknown = 0
    case Hz = 1
    case GPM = 2
    case M3_Hour = 3
    case mA = 4
    case PSI = 5
    case Bar = 6
    var toString : String {
        return self == .M3_Hour ? "m³/hr" : "\(self)"
    }
}

I'm not seeing any recursion for that. (However I should add that I see this fragile; we are relying on a feature that might not work in the future. Apple can change the description of an object at any time.)

But the real answer is that either you should use a String raw value instead of an Int raw value, or else you should provide a complete switch over all the cases, associating each case with a usable string.

matt
  • 515,959
  • 87
  • 875
  • 1,141
1

Comments about style and work arounds appreciated. The answer I was looking for came from the Swift Forums and was as simple as:

Unfortunately, you can't. The function you'd need to call is internal to the standard library.

So basically, the machinery that does the fallback conversion from enums to their as-coded-strings when you don't provide your own description implementation is not available.

(Which @matt also said in the comments, and if he'd made that an answer, I would have added even more points to his vast surplus of reputation)

Travis Griggs
  • 21,522
  • 19
  • 91
  • 167
0

This works for me, hope this is what you have expected.

enum UnitCode: UInt {
    case Unknown = 0
    case Hz = 1
    case GPM = 2
    case M3_Hour = 3
    case mA = 4
    case PSI = 5
    case Bar = 6
}

let anUnit: UnitCode = .M3_Hour

extension UnitCode: CustomStringConvertible {
    var description: String {
        switch self {
        case .M3_Hour:
            return "m³/hr"
        default:
            return String(describing: self)
        }
    }
}

print(anUnit.self)
//m³/hr
infinity_coding7
  • 434
  • 5
  • 16
  • It's not, sorry. I would still want the other cases to just do the "standard" thing, not be flattened to "blahblah". And I was trying to avoid enumerating all of the cases, but rather access the base/default machinery that stringifies enums. – Travis Griggs Jun 02 '21 at 22:25