appendInterpolation<T>(_ value: T?) would match any optional interpolation with a single argument.
Interpolations distinguished only by type can be confusing to the user, so I prefer using argument labels or at least multiple arguments in some canonical fashion.
Nil is one case of failure, but failure can include false Bool, empty string, etc. Giving all success/fail interpolations the same parameters makes it easier for users.
For any success/fail interpolation, I'd like to supply an alternate String in case of failure, and prefix/suffix in case of success.
So this is my interface for optionals:
public mutating func appendInterpolation<T>(
_ prefix: String?,
_ item: T?,
_ suffix: String? = "",
alt: String = ""
) { ... }
Sample uses:
// "\(foo)" or "" (using default alt value)
"\("", foo)"
// "f(\(args))" or "n/a"
"\("f(", args, ")", alt: "n/a")"
Here's a separate one for String, so failure can include the empty string (perhaps even after removing whitespace):
public mutating func appendInterpolation(
_ prefix: String?,
_ item: String?, // same for nil or empty
_ suffix: String? = "",
alt: String = ""
) { ... }
And here's Bool in the same position:
public mutating func appendInterpolation(
_ prefix: String?,
_ doPrint: Bool,
_ suffix: String? = "",
alt: String = ""
) { ... }
In the Bool case, an alt value is almost always specified for the false case, except when using an expression to silence a value.
You can manage sequences/collections similarly (e.g., with different results for nil, empty, single, and many).
And you can use interpolation in the arguments:
// "" or "Summary: \(summary)" or "Summary: \(summary) {\(details)}"
"\("Summary: ", summary, "\(" {", details, "}")")"
// "[P2] r3.0.alpha FIXED" or "jane@dev.ours.com"
"\("[\(bug.priority)]", bug.release, "\(bug.resolution)", alt: "\(bug.assignee)")"
(Also consider replicating the system privacy argument when supporting possibly-private output.)