String Interpolation and Specifier Formatting in Playgrounds

In my macOS SwiftUI app I've been able to write code like this:

    Text("Yl: \(self.local.y, specifier: "%0.f")")

Which I thought meant Swift finally had support right in the interpolation for printf-style format specifiers.

But I just tried to use in a Playground

print("Took \(end - start, specifier: "%0.f") s")

and I get error: extra argument 'specifier' in call. I tried googling this but everyone who talks about formatting in string interpolation seems to have older articles. But as I write this, I've discovered what I think is going on. That form of string interpolation is only available in LocalizedStringKey, is that right?

Wouldn't it make sense to just add this to ExpressibleByStringInterpolation and make it part of the standard library?

That would be correct. In particular, it is its conformance to ExpressibleByStringInterpolation.

But does String not conform to ExpressibleByStringInterpolation? I'm a bit fuzzy on what happens when I type a string literal in Swift, but I don't get why I can't do this with print.

In fact, I only saw the specifier variant on LocalizedStringKey, not on ExpressibleByStringInterpolation.

The protocol has an associated type StringInterpolation, which defines permissible variations of \(value). In particular,

  • String uses DefaultStringInterpolation, and
  • LocalizedStringKey uses LocalizedStringKey.StringInterpolation.

If, for example, you'd like to add \(blah: x) to String, you add it to DefaultStringInterpolation:

extension DefaultStringInterpolation {
  func appendInterpolation(blah: Int) { ... }
}

let x: String = "\(blah: 0)" // ok
let y: LocalizedStringKey = "\(blah: 0)" // error

The StringInterpolation generally has the interpolation side, and the write-out side, there is DefaultStringInterpolation.write that you can use to read the finalized result. Unfortunately, LocalizedStringKey.StringInterpolation seems to have them behind the private curtain.

Would it make sense to pitch for including appendInterpolation(_:specifier:) in the core language?

Pretty much any thing would so long as you can justify them being added (and I won't be the judge here). That's why ppl usually start out by pitching it to gauge the response.

1 Like

I've never actually done that. Do I just start a post with "Pitch: add blah blah"?

The details are in How to Propose a Change, but yeah, usually that's a start, to see if ppl would like it, and see if there's someone willing to implement it.

PS

Actually, pitching to #evolution:pitches is Step 3 in the link, though I don't think anyone pitched similar thing before, so that's Step 1 done.

1 Like

Could they've done it this way and have the same interpolations available in both String and LocalizedStringKey?

Update: No I think because the LocalizedStringKey version needs to work out the localizable key and is probably go through the localization machinery to do its formatting...where as the String version needs only produce the String result, this can probably use String.init(format:...)

OSLog has an extensive set of string interpolation capability:

///     os_log(
///       .error,
///       log: customLog,
///       "An unsigned integer \(x, format: .hex, align: .right(columns: 10))")
///
///     os_log(.fault, log: customLog, "unsigned value \(x, privacy: .private)")

can these be made available to String?

Terms of Service

Privacy Policy

Cookie Policy