How can I check if Enum type conforms to CustomStringConvertable Protocol?

enum Vehicles: Int {
       case car = 1
       case bus
       case taxi
    
       var kind: String {
           String(describing: self)
       }
}

if let v = Vehicles(rawValue: 2) {
  print("\(v.kind)")
}

When I run this code "bus" is printed in debug log by String(describing: self).
As far as I know in order to support String(describing) the enum type must conform to CustomStringConvertible, right?

How can I check if Enum type conforms to CustomStringConvertable Protocol?
I've searched swift standard library source codes but I was not able to find any files about enum type.

Incorrect. No conformance is necessary, everything can be turned into a string that way (or through string interpolation).

CustomStringConvertible just means the type has provided its own custom conversion to a string, instead of using the compiler’s default description. You essentially never want to write code that cares about CustomStringConvertible.

Thank you for the answer. @Nevin

BTW, I don't fully understand.

What do you mean by using compiler's default description.
Anyway, Isn't is supposed to be declared in somewhere?

In case of String, it is declared in extension of String like following code in Swift Standard Library.

extension String: CustomStringConvertible {
  /// The value of this string.
  ///
  /// Using this property directly is discouraged. Instead, use simple
  /// assignment to create a new constant or variable equal to this string.
  @inlinable
  public var description: String { return self }
}

So I tried to find something like below from Swift Standard Library to see if enum is declared as same with String. But I was not able to find anything about it.

extension Enum: CustomDebugStringConvertible {
}
...

I suspect that enum is related to enum of Objective-C so it is located in somewhere else.
But I don't know much about it.

IIRC it calls _print_unlocked which uses Mirror for printing if the type doesn’t conform to TextOutputStreamable, CustomStringConvertible, etc (although there are fast paths for these as well).

1 Like

String(describing:) will take any type and turn it into a string. Every value in Swift is convertible to a string, regardless of a type’s conformance to the CustomDebugStringConvertible protocol. The protocol exist only to allow customization of a type’s string representation.

When you call String(describing:) it calls _print_unlocked under the hood, which performs a series of tests on the type to find out how to turn it into a string.

The function looks like this:

internal func _print_unlocked<T, TargetStream : TextOutputStream>(
  _ value: T, _ target: inout TargetStream
) {
  if _isOptional(type(of: value)) {
    let debugPrintable = value as! CustomDebugStringConvertible
    debugPrintable.debugDescription.write(to: &target)
    return
  }
  if case let streamableObject as TextOutputStreamable = value {
    streamableObject.write(to: &target)
    return
  }
   
  if case let printableObject as CustomStringConvertible = value {
    printableObject.description.write(to: &target)
    return
  }
   
  if case let debugPrintableObject as CustomDebugStringConvertible = value {
    debugPrintableObject.debugDescription.write(to: &target)
    return
  }
   
  let mirror = Mirror(reflecting: value)
  _adHocPrint_unlocked(value, mirror, &target, isDebugPrint: false)
}

As you can see, it will default to using Mirror if all tests fail. This is the case for your enum unless you explicitly conform to the protocol to opt in to customization.

Ah, I see. Thank you so much! @sveinhal
It's very helpful to understand how it's working on under the hood.