> 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

Reply via email to