Using string interpolation for items within collections

I'm still coming to grips with the new appendInterpolation() feature in Swift 5.

From my experimentation, it appears that my String extensions are producing the appropriate print statements for my types, but aren't being used when I am trying to print a collection of a type (such as an array).

Is there a trick to this, or is it simply something which isn't catered for?

It's hard to say what your problem is without seeing any of your code, but maybe you're confused by the fact that printing the object uses description, and printing an array uses debugDescription?

struct Foo: CustomStringConvertible, CustomDebugStringConvertible {
    var description: String { "A" }
    var debugDescription: String { "B" }
}

let foo = Foo()
let fooArray = [Foo()]

print(foo) // A
print(fooArray) // [B]
1 Like

I did consider throwing some code in there, but as it was real vanilla stuff I didn't imagine it added anything. But here is what I used as a test.

struct A
{
	let x = 5
}

let a = A()
print(a)
print("\(a)")

let b = [a]
print(b)
print("\(b)")

extension String.StringInterpolation
{
	mutating func appendInterpolation(_ c: A)
	{
		appendLiteral("Value is ")
		appendInterpolation(c.x)
	}
}

The output I get is…
A(x: 5)
Value is 5
[__lldb_expr_16.A(x: 5)]
[__lldb_expr_16.A(x: 5)]

So as you can see, while the struct prints fine in line #2, it doesn't when in an array. I find that it will work if I create an interpolation format for an array as well, but that just seems rather unnecessary.

Array<A> is something different from A, so if you want to have customized interpolation for both, you have to implement it for both.

Granted, it is. However one would imagine that printing [A] would automatically have the array calling the A interpolation for each element. After all, that's what it does with CustomStringConvertable.

In any case, I'm guessing the answer to my question is that there isn't any automatic way of doing it?

As far as I know there isn't any

The cause is Swift standard library collections are not simply interpolating their elements, they use debugDescription. EG the implementation of Array's description (for CustomStringConvertible conformance) will look something like

self.map { $0.debugDescription }.joined(",") // obv not real

In general, relying on string interpolation overloads to affect printing logic of types you don't control is probably not ideal. You should implement CustomStringConvertible and CustomDebugStringConvertible directly on A.

Ok. Thank you both for your inputs. Obviously not the answer I was hoping for, but at least I know it isn't something I'm overlooking.

I've gone back to using CustomStringConvertable, but was interested in trying out the interpolation given it felt like the more modern approach.

Seeing StringInterpolation as the 'new' alternative isn't quite right. It's complementary and better for some circumstances, mostly when you are dealing with a type that you control (ie SQLExpression.StringInterpolation) rather than a standard library thing, or if you are trying to add custom interpolations with additional parameters and such. But baseline printing behaviour is the purpose of Custom[Debug]StringConvertible. Hope that helps.