Question re: String.init(describing:) overloads: why there are four?

I think it all comes down to efficiency and correctness. The source code for the initializers show that they have different implementations for different Subject.

Let me label the 4 initializers, so they're more wieldy:

// initializer 1
init<Subject>(describing instance: Subject) where Subject: TextOutputStreamable
// initializer 2
init<Subject>(describing instance: Subject) where Subject: CustomStringConvertible
// initializer 3
init<Subject>(describing instance: Subject) where Subject: CustomStringConvertible, Subject: TextOutputStreamable
// initializer 4
init<Subject>(describing instance: Subject)

TextOutputStreamable and CustomStringConvertible are 2 protocols that each allows the user to provide a description for an instance of a type. Initializers 1 and 2 take advantage of their existence, and use the user-defined value as the instance's description. 1 and 2 are implemented differently, because the "description" part of TextOutputStreamable and CustomStringConvertible are implemented differently: TextOutputStreamable uses write(to:) and CustomStringConvertible uses description.

Because initializers 1 and 2 are implemented differently, 3 becomes necessary for the compiler to know what to do when Subject conforms to both CustomStringConvertible and TextOutputStreamable.

4 (the most general case?) uses reflection to create a description of an instance, regardless of its type.

Initializers 1, 2. and 3 exist when 4 already works for all Subjects, because it's more efficient (and correct?) to use what the user has provided, instead of finding out an instance's description through reflection.

For the same reason, there are multiple overloads of appendInterpolation in DefaultStringInterpolation.

4 Likes