1

When specifically dealing with non-optional String values, what could be the difference between String interpolation and String concatenation?

struct MyModel {
    let value1: String
    let value2: String
    var displayNameByConcatenation: String {
        return value1 + "-" + value2
    }
    var displayNameByInterpolation: String {
        return "\(value1)-\(value2)"
    }
}
  • Is there going to be any case where displayNameByConcatenation and displayNameByInterpolation are different? Like on long unicode strings?
  • Is it possible to somehow override the behavior of operator + or the behavior of interpolation to make them different in above example?
  • Is one faster/slower than the other?

Note that from this question we learn that string interpolation will use the description of a CustomStringConvertible. But does String concatenation (operator +) also calls the description?

Community
  • 1
  • 1
Cœur
  • 37,241
  • 25
  • 195
  • 267

3 Answers3

6

From a speed point of view, to differentiate concatenation (value1 + "-" + value2) and interpolation ("\(value1)-\(value2)"), results may depend on the number of operations done to obtain the final string.

My results on an iPhone 8 show that:

  • if there is roughly < 30 substrings to attach together, then concatenation is faster
  • if there is roughly > 30 substrings to attach together, then interpolation is faster

Thank you Sirens for figuring out that one wasn't always faster than the other!

Try it yourself (and don't forget to adapt the tested character set and iterations for your needs):

import UIKit

class ViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        DispatchQueue.global(qos: .default).async {
            ViewController.buildDataAndTest()
        }
    }

    private static func buildDataAndTest(times: Int = 1_000) {
        let characterSet = CharacterSet.alphanumerics
        characterSet.cacheAllCharacters()
        let data: [(String, String)] = (0 ..< times).map { _ in
             (characterSet.randomString(length: 50), characterSet.randomString(length: 20))
        }
        _ = testCIA(data)
        _ = testInterpol(data)
        print("concatenation: " + String(resultConcatenation))
        print("interpolation: \(resultInterpolation)")
    }

    /// concatenation in array
    static var resultConcatenation: CFTimeInterval = 0
    private static func testCIA(_ array: [(String, String)]) -> String {
        var foo = ""
        let start = CACurrentMediaTime()
        for (a, b) in array {
            foo = foo + " " + a + "+" + b
        }
        resultConcatenation = CACurrentMediaTime() - start
        return foo
    }

    /// interpolation
    static var resultInterpolation: CFTimeInterval = 0
    private static func testInterpol(_ array: [(String, String)]) -> String {
        var foo = ""
        let start = CACurrentMediaTime()
        for (a, b) in array {
            foo = "\(foo) \(a)+\(b)"
        }
        resultInterpolation = CACurrentMediaTime() - start
        return foo
    }
}

extension CharacterSet {
    static var cachedCharacters: [Character] = []

    public func cacheAllCharacters() {
        CharacterSet.cachedCharacters = characters()
    }

    /// extracting characters
    /// https://stackoverflow.com/a/52133647/1033581
    public func characters() -> [Character] {
        return codePoints().compactMap { UnicodeScalar($0) }.map { Character($0) }
    }
    public func codePoints() -> [Int] {
        var result: [Int] = []
        var plane = 0
        for (i, w) in bitmapRepresentation.enumerated() {
            let k = i % 8193
            if k == 8192 {
                plane = Int(w) << 13
                continue
            }
            let base = (plane + k) << 3
            for j in 0 ..< 8 where w & 1 << j != 0 {
                result.append(base + j)
            }
        }
        return result
    }

    // http://stackoverflow.com/a/42895178/1033581
    public func randomString(length: Int) -> String {
        let charArray = CharacterSet.cachedCharacters
        let charArrayCount = UInt32(charArray.count)
        var randomString = ""
        for _ in 0 ..< length {
            randomString += String(charArray[Int(arc4random_uniform(charArrayCount))])
        }
        return randomString
    }
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
  • I'd run this test many times though, to make sure this claim is statistically valid. – Dielson Sales Mar 14 '18 at 19:07
  • I'm getting inverse results on my iPad Pro. concatenation takes 8.51 where as interpolation takes 1.99. Swift 4.1, `-O -Ofast` – Allison Jan 13 '19 at 07:15
  • I presume that your output above is for a single iteration which did not incorporate @DielsonSales suggestion. This was done on the 2018 iPad Pro on 12.1 – Allison Jan 13 '19 at 07:55
  • @Sirens thank you for noticing: post updated to reflect that depending on the number of iterations, it's not always the same one which is the fastest. – Cœur Feb 12 '19 at 03:36
0

string interpolation:

  • less typing
  • Internally calls to string
  • faster during the run time

one disadvantage:

  • delimit your string

Both interpolation and concatenation has its own strength and weakness

Need to use concatenation with predefined string to get better performance

Nattudurai
  • 856
  • 7
  • 9
  • so string interpolation is faster? is it from tests, from documentation or from logic deduction? – Cœur Mar 17 '17 at 05:52
  • if its dynamic string - interpolation is faster by tests. u can use numbers, enum, etc on interpolation – Nattudurai Mar 17 '17 at 08:49
0

"Concatenation allows you to combine to strings together and it only works on two strings."

An update. Not sure what earlier versions of Swift allowed, but currently you can concatenate more than 2 Strings together in the same statement:

let str = "Hi, my name is "

var concat = str + "2" + "3" + "4" + "5" + " works" //displays "Hi, my name is 2345 works"

Because both operands of + need to be Strings, you have to do a little extra work if you want to add a number to a String:

var concat2 = str + String(2) //displays "Hi, my name is 2"

Reason why interpolation rather than concatenation, here's a quote from Apple's intro for interpolation: "String interpolation is a way to construct a new String value from a mix of constants, variables, literals, and expressions" In other words, you can use interpolation with numbers, booleans, etc. without first turning them into Strings, which you would have to do if you used concatenation.

Saumil Shah
  • 2,299
  • 1
  • 22
  • 27
  • This seems to be a direct quote of the post by Pasan Premaratne found here. https://teamtreehouse.com/community/what-is-the-difference-between-concatenation-and-interpolation-it-seems-like-you-can-do-the-exact-same-thing-with-both – Neil Meyer Mar 07 '18 at 09:47