> On Mar 10, 2017, at 11:27 AM, David Waite <da...@alkaline-solutions.com> > wrote: > >> >> On Mar 10, 2017, at 9:49 AM, Joe Groff via swift-evolution >> <swift-evolution@swift.org> wrote: >> >> Having ExpressibleByStringInterpolation refine ExpressibleByStringLiteral >> makes sense. I think there's a more powerful alternative design you should >> also consider. If the protocol looked like this: >> >> protocol ExpressibleByStringInterpolation: ExpressibleByStringLiteral { >> associatedtype LiteralSegment: ExpressibleByStringLiteral >> associatedtype InterpolatedSegment >> init(forStringInterpolation: Void) >> >> mutating func append(literalSegment: LiteralSegment) >> mutating func append(interpolatedSegment: InterpolatedSegment) >> } >> >> Then an interpolation expression like this in `Thingy` type context: >> >> "foo \(bar) bas \(zim: 1, zang: 2)\n" >> >> could desugar to something like: >> >> { >> var x = Thingy(forStringInterpolation: ()) >> // Literal segments get appended using append(literalSegment: "literal") >> x.append(literalSegment: "foo ") >> // \(...) segments are arguments to a InterpolatedSegment constructor >> x.append(interpolatedSegment: Thingy.InterpolatedSegment(bar)) >> x.append(literalSegment: " bas ") >> x.append(interpolatedSegment: Thingy.InterpolatedSegment(zim: 1, zang: 2)) >> >> return x >> }() >> >> This design should be more efficient, since there's no temporary array of >> segments that needs to be formed for a variadic argument, you don't need to >> homogenize everything to Self type up front, and the string can be built up >> in-place. It also provides means to address problems 3 and 4, since the >> InterpolatedSegment associated type can control what types it's >> initializable from, and can provide initializers with additional arguments >> for formatting or other purposes. > > Hi Joe, > > The trade-offs for this approach would be: > - each append would need to return a valid object w.r.t the type’s invariants. > - an implementation could use the init(stringInterpolation:) could be a final > building step, while append would not indicate that the object construction > was complete. > One example where this could be a problem would be if someone used the > segments to build up a localized representation of the interpolated string.
Validation is a general problem with the literal protocols, since none of the literal protocols allow for failed initialization, and if you can write "foo \(bar) bas", you can write "foo " or "foo \(bar)", so you need to have a representation for those intermediate states already. I think allowing the literal and interpolated types to be different is important. You could achieve that with an initializer that took a variadic list of enums, perhaps: protocol ExpressibleByStringInterpolation: ExpressibleByStringLiteral { associatedtype LiteralSegment: ExpressibleByStringLiteral associatedtype InterpolatedSegment enum Segment { case literal(LiteralSegment), interpolated(InterpolatedSegment) } init(stringInterpolation: Segment...) } That still requires the argument array to be constructed up front, though. -Joe _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution