$30 off During Our Annual Pro Sale. View Details »

Swift 5's Custom String Interpolation in Practice

Bas Broek
February 06, 2020

Swift 5's Custom String Interpolation in Practice

Bas Broek

February 06, 2020
Tweet

More Decks by Bas Broek

Other Decks in Programming

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