Swift 5's Custom String Interpolation in Practice

79fe3c13c618a61329298bdd6a86ec42?s=47 Bas Broek
February 06, 2020

Swift 5's Custom String Interpolation in Practice

79fe3c13c618a61329298bdd6a86ec42?s=128

Bas Broek

February 06, 2020
Tweet

Transcript

  1. Using Swift 5's Custom String Interpolation in Practice @basthomas, Copenhagen

    Cocoa, 06-02-2020 1
  2. Who am I • Swift Weekly Brief • Contravariance (stickers)

    • RayWenderlich tech editor • iOS Platform at XING @basthomas, Copenhagen Cocoa, 06-02-2020 2
  3. Where do we come from? @basthomas, Copenhagen Cocoa, 06-02-2020 3

  4. ! @basthomas, Copenhagen Cocoa, 06-02-2020 4

  5. NSString *name = @"Bas"; [NSString stringWithFormat:@"Hello, %@", name]; [NSString stringWithFormat:@"%.2f",

    9.0234]; [NSString stringWithFormat: @"Hello %@, how are you doing this %@? %@", @"Bas", @"evening", @"Great!" ]; @basthomas, Copenhagen Cocoa, 06-02-2020 5
  6. ✨ @basthomas, Copenhagen Cocoa, 06-02-2020 6

  7. let name = "Bas" "Hello, \(name)" String(format: "%.2f", 9.0234) //

    "Hello \(name), how are you doing this \(timeOfDay)?" @basthomas, Copenhagen Cocoa, 06-02-2020 7
  8. It is very good. @basthomas, Copenhagen Cocoa, 06-02-2020 8

  9. Interlude @basthomas, Copenhagen Cocoa, 06-02-2020 9

  10. Swift Evolution @basthomas, Copenhagen Cocoa, 06-02-2020 10

  11. Multiline String Literals (SE-0168) """ Hello, how are you doing

    this \(timeOfDay)? """ @basthomas, Copenhagen Cocoa, 06-02-2020 11
  12. String Literal Delimiters (SE-0200) // before "\"Did you put your

    name into the Goblet of Fire, Harry?\" he asked calmly." // after #""Harry! Did you put your name in the Goblet of Fire?!""# @basthomas, Copenhagen Cocoa, 06-02-2020 12
  13. And then... @basthomas, Copenhagen Cocoa, 06-02-2020 13

  14. Custom String Interpolation (aka Fix ExpressibleByStringInterpolation) @basthomas, Copenhagen Cocoa, 06-02-2020

    14
  15. Localization @basthomas, Copenhagen Cocoa, 06-02-2020 15

  16. let message: LocalizableString = #"The document "\(name)" could not be

    saved."# alert.messageText = String(localized: message) @basthomas, Copenhagen Cocoa, 06-02-2020 16
  17. Errors @basthomas, Copenhagen Cocoa, 06-02-2020 17

  18. extension String.StringInterpolation { mutating func appendInterpolation(_ error: Error) { appendLiteral(error.localizedDescription)

    } } fatalError( "Something went wrong: \(ConnectionError.invalidRequest)" ) @basthomas, Copenhagen Cocoa, 06-02-2020 18
  19. Number formatting @basthomas, Copenhagen Cocoa, 06-02-2020 19

  20. extension String.StringInterpolation { mutating func appendInterpolation( number: Double, formatter: NumberFormatter

    ) { appendInterpolation( ifNotNil: formatter.string(from: NSNumber(value: number)) ) } } let priceFormatter = NumberFormatter() priceFormatter.numberStyle = .currency "\(number: 100.1234, formatter: priceFormatter)" @basthomas, Copenhagen Cocoa, 06-02-2020 20
  21. Logging and privacy @basthomas, Copenhagen Cocoa, 06-02-2020 21

  22. extension String.StringInterpolation { mutating func appendInterpolation(private: String) { #if DEBUG

    appendLiteral(`private`) #else appendLiteral("@@@") #endif } } let name = "Bas" let password = "Broek" print("User \(name) has password \(private: password)") @basthomas, Copenhagen Cocoa, 06-02-2020 22
  23. Other instances @basthomas, Copenhagen Cocoa, 06-02-2020 23

  24. "\(properties == nil ? "nil" : String(describing: properties ?? [:]))"

    @basthomas, Copenhagen Cocoa, 06-02-2020 24
  25. extension String.StringInterpolation { mutating func appendInterpolation( dictionary: Dictionary<AnyHashable, Any>?, default:

    @autoclosure () -> String = "nil" ) { if let dictionary = dictionary { appendLiteral(String(describing: dictionary)) } else { appendLiteral(`default`()) } } } "\(dictionary: properties)" @basthomas, Copenhagen Cocoa, 06-02-2020 25
  26. 123 > maxBadgeCount ? String("\(maxBadgeCount)+") : String(123) @basthomas, Copenhagen Cocoa,

    06-02-2020 26
  27. extension String.StringInterpolation { mutating func appendInterpolation( number: Int, maximum: @autoclosure

    () -> Int ) { let max = maximum() if number > max { appendLiteral("\(max)+") } else { appendLiteral("\(number)") } } } "\(number: number, maximum: maxBadgeCount)" @basthomas, Copenhagen Cocoa, 06-02-2020 27
  28. ! @basthomas, Copenhagen Cocoa, 06-02-2020 28

  29. Polluting a namespace @basthomas, Copenhagen Cocoa, 06-02-2020 29

  30. Code, documentation, tests @basthomas, Copenhagen Cocoa, 06-02-2020 30

  31. struct BadgeCount: CustomStringConvertible { let value: Int var maximum =

    99 var description: String { if value > maximum { return "\(maximum)+" } else { return "\(value)" } } } "\(BadgeCount(value: 123, maximum: 99))" "\(BadgeCount(value: 123))" @basthomas, Copenhagen Cocoa, 06-02-2020 31
  32. Going all in @basthomas, Copenhagen Cocoa, 06-02-2020 32

  33. struct HTMLComponent: ExpressibleByStringLiteral, ExpressibleByStringInterpolation, CustomStringConvertible { struct StringInterpolation: StringInterpolationProtocol {

    var output = "" init(literalCapacity: Int, interpolationCount: Int) { output.reserveCapacity(literalCapacity * 2) } mutating func appendLiteral(_ literal: String) { output.append(literal) } mutating func appendInterpolation(twitter: String) { output.append("<a href=\"https://twitter.com/\(twitter)\">@\(twitter)</a>") } mutating func appendInterpolation(email: String) { output.append("<a href=\"mailto:\(email)\">\(email)</a>") } } let description: String init(stringLiteral value: String) { description = "<p>\(value)</p>" } init(stringInterpolation: StringInterpolation) { self.init(stringLiteral: stringInterpolation.output) } } @basthomas, Copenhagen Cocoa, 06-02-2020 33
  34. struct StringInterpolation: StringInterpolationProtocol { var output = "" init(literalCapacity: Int,

    interpolationCount: Int) { output.reserveCapacity(literalCapacity * 2) } mutating func appendLiteral(_ literal: String) { output.append(literal) } mutating func appendInterpolation(twitter: String) { output.append("<a href=\"https://twitter.com/\(twitter)\">@\(twitter)</a>") } mutating func appendInterpolation(email: String) { output.append("<a href=\"mailto:\(email)\">\(email)</a>") } } let html: HTMLComponent = "Find me on \(twitter: "basthomas") or send an email to \(email: "bas@basbroek.nl")" // <p>Find me on <a href="https://twitter.com/basthomas">@basthomas</a> // or send an email to <a href="mailto:bas@basbroek.nl">bas@basbroek.nl</a></p> @basthomas, Copenhagen Cocoa, 06-02-2020 34
  35. Optimize code for reading, not writing @basthomas, Copenhagen Cocoa, 06-02-2020

    35
  36. Communication is hard @basthomas, Copenhagen Cocoa, 06-02-2020 36

  37. Thanks! @basthomas @basthomas, Copenhagen Cocoa, 06-02-2020 37