14

I want to have my enums easily compatible with @IBInspectable, so for the sake of simplicity, I tried to have it representable with type Bool:

enum TopBarStyle: Bool {
    case darkOnLight
    case lightOnDark
}

But Xcode is giving me:

Raw type 'Bool' is not expressible by any literal

That's strange, as true and false seem to be perfect candidates for expressibility by literals.

I've also tried to add RawRepresentable conformance to type Bool with:

extension Bool: RawRepresentable {
    public init?(rawValue: Bool) {
        self = rawValue
    }
    public var rawValue: Bool {
        get { return self }
    }
}

But it didn't solve the error.

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • 7
    The documentation is pretty clear: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID149: *"Raw values can be strings, characters, or any of the integer or floating-point number types.* – Martin R Feb 17 '17 at 07:51
  • You could achieve the same effect by adding a computed `var boolValue` on the enum. – Connor Neville Feb 17 '17 at 13:09
  • 1
    To add to @MartinR's comment, `true` and `false` aren't literals; they're closer to constants (constants whose names are reserved by the compiler). A literal is something that the compiler has some magic to convert to an internal value. There is no magic necessary to make sense of `true` and `false`, as they're keywords. – BallpointBen Feb 26 '17 at 05:03

5 Answers5

16

Swift 3 natively defines those nine literal representations:

  • ExpressibleByNilLiteral (nil)
  • ExpressibleByBooleanLiteral (false)
  • ExpressibleByArrayLiteral ([])
  • ExpressibleByDictionaryLiteral ([:])
  • ExpressibleByIntegerLiteral (0)
  • ExpressibleByFloatLiteral (0.0)
  • ExpressibleByUnicodeScalarLiteral ("\u{0}")
  • ExpressibleByExtendedGraphemeClusterLiteral ("\u{0}")
  • ExpressibleByStringLiteral ("")

But enum raw representation will apparently only accept natively the subset of those representions that start with a digit (0-9), a sign (-, +) or a quote ("): the last five protocols of above list.

In my opinion, the error message should have been more specific. Maybe something explicit like that would have been nice:

Raw type 'Bool' is not expressible by any numeric or quoted-string literal

Extending Bool to conform to one of those protocols is still possible, for example:

extension Bool: ExpressibleByIntegerLiteral {
    public init(integerLiteral value: Int) {
        self = value != 0
    }
}

And after doing so, this code now builds fine:

enum TopBarStyle: Bool {
    case darkOnLight
    case lightOnDark
}

@IBInspectable var style = TopBarStyle(rawValue: false)!
Cœur
  • 37,241
  • 25
  • 195
  • 267
14

my solution on swift 3

enum DataType: RawRepresentable {
    case given
    case received

    typealias RawValue = Bool
    var rawValue: RawValue {
        return self == .given ? true : false
    }
    init?(rawValue: RawValue) {
        self = rawValue == true ? .given : .received
    }
}
Duck
  • 34,902
  • 47
  • 248
  • 470
EvGeniy Ilyin
  • 1,817
  • 1
  • 21
  • 38
7

Simplify your life:

enum TopBarStyle {
    case darkOnLight
    case lightOnDark

    var bool: Bool {
        switch self {
        case .darkOnLight:
            return true
        default:
            return false
        }
    }
}

Use as usual:

    var current = TopBarStyle.darkOnLight

    if current.bool {
        // do this
    } else {
        // do that
    }

You can extend cases to more but they are not reversible since its an N : 2 matrix

  • 2
    That doesn't make it compatible with `@IBInspectable`. So in that regard, the accepted answer is more helpful. – Cœur Apr 21 '19 at 12:06
  • Why you want to use an Extra '.bool' when swift RawRepresentable provides you the flexibility. – infiniteLoop Oct 22 '21 at 06:32
  • I recreated this to make it easier for me to access certain predefined SCNVector3 values. Super good answer! – ZAY Dec 21 '21 at 08:24
  • Is it possible to print out the variable name that is equal to true? In this case print `darkOnLight` because it's the variable with the true boolean. Would the `Mirror` type help in this case? – Edison Oct 09 '22 at 12:31
4

I don't think this is necessary. You can just make a normal enum and then switch over its cases. Also, it's not clear at all what TopBarStyle(rawValue: true) would mean if this could be achieved.

I would either use var darkOnLight: Bool, or enum TopBarStyle { /*cases*/ } and switch over the cases as necessary.

BallpointBen
  • 9,406
  • 1
  • 32
  • 62
0

Working example in Swift 5:

public enum MyBoolEnum: CaseIterable, RawRepresentable {

    case yes
    case no

    public init?(rawValue: Bool) {
        self = rawValue ? .yes : .no
    }

    public var rawValue: RawValue {
        switch self {
        case .yes:
            return true
        case .no:
            return false
        }
    }
}
Bogdan Razvan
  • 1,497
  • 1
  • 16
  • 16