ExpressibleByStringInterpolation with #file and #line

Is there a way to pass #file and #line into an instance of a type conforming to ExpressibleByStringInterpolation when it is only initialized by a string? For example, an instance of the type

struct Example {
    let code: String
    let file: StaticString
    let line: UInt

    init(code: String, file: StaticString = #file, line: UInt = #line) {
        self.code = code
        self.file = file
        self.line = line
    }
}

can be initialized by let example = Example("let a = 1"). It knows from which file and line it comes as file and line will be populated by the default arguments.

Now, it would be quite handy to have Example conform to ExpressibleByStringInterpolation so that I can just write let example: Example = "let a = 1" to initialize an example:

extension Example: ExpressibleByStringInterpolation {
    public init(stringLiteral code: String) {
        self.init(code: code)
    }
}

However, logically #file and #line will refer to the init(stringLiteral:) initializer, not the place where example is created which I would like to have instead. Is there a way to achieve this?

if you write it like that that would be a string, to make it Example you'd need a type annotation:

let example: Example = "let a = 1"
let example = Example("let a = 1")

Compare the two lines, did you win anything?

A better example would be:

var example: Example = ...
....
example = "let a = 1"

no joy here with file/line. You could use a workaround:

example.set("let a = 1")

where set takes additional defaulted file / line parameters.
An additional benefit – it will allow chaining style (like in SwiftUI) if you are into it.

As a side note consider using #fileID instead of #file, you may like that better.

You are right. I missed the type annotation in let example: Example = "let a = 1". Fixed it.

It's clear that let example: Example = ... isn't any better than let example = Example(...). If instances of the type are often passed to methods as lists of examples (like in my case), it's a bit cleaner if the types can be omitted and there are only strings in the list.

1 Like