Why does string concatenation with + cause a compiler error in EK9?

← Common String Operations · Ref: Q309

EK9 enforces string interpolation over concatenation chains. If you concatenate 3 or more parts with the + operator where the result is a String, the compiler produces error E11068: PREFER_STRING_INTERPOLATION.

WHY IT IS AN ERROR

Each + on strings calls the _add operator, creating a new intermediate String. A chain of N concatenations creates N-1 temporary objects. String interpolation compiles to a bespoke STRING_INTERPOLATION IR instruction that backends optimise to one allocation:

  JVM: invokedynamic StringConcatFactory.makeConcatWithConstants()
  LLVM: single allocation with pre-calculated length + memcpy

Beyond performance, interpolation shows the output shape directly. Concatenation requires mentally assembling fragments separated by + operators.

WHAT TRIGGERS E11068

A chain of 3+ parts where the result type is String:

  result <- "Hello " + name + "!"         3 parts: error
  result <- a + " " + b + " " + c         5 parts: error
  result <- prefix() + text + "]"          3 parts: error

WHAT DOES NOT TRIGGER E11068

  result <- first + second                  2 parts: allowed
  total <- a + b + c                        numeric +: not String type
  combined <- list1 + list2 + list3         list +: not String type

HOW TO FIX

Convert the concatenation chain to string interpolation:

  BAD:  result <- "Hello " + name + "!"
  GOOD: result <- `Hello ${name}!`
  BAD:  result <- host + ":" + $port
  GOOD: result <- `${host}:${$port}`
  BAD:  result <- "(" + $x + ", " + $y + ")"
  GOOD: result <- `(${$x}, ${$y})`

Use the $ operator inside ${...} to convert non-String values.

See Q174 for all string combination methods. See Q37 for string basics. See Q43 for escape sequences and literal dollar signs in interpolation.

Example

defines module qa.stringops.preferinterpolation

  defines function

    // Two-part concatenation is allowed
    twoPartConcat()
      ->
        first as String
        second as String
      <- result as String: first + second

    // Interpolation for 3+ parts
    greetPerson()
      -> name as String
      <- result as String: `Hello ${name}!`

    // Mixed types with $ operator
    formatEndpoint()
      ->
        host as String
        port as Integer
      <- result as String: `${host}:${port}`

    // Complex interpolation
    formatCoordinate()
      ->
        x as Integer
        y as Integer
      <- result as String: `(${x}, ${y})`

  defines program
    InterpolationDemo()
      stdout <- Stdout()

      // Two-part concat is fine
      stdout.println(twoPartConcat("Hello", "World"))

      // Interpolation for everything else
      stdout.println(greetPerson("Steve"))
      stdout.println(formatEndpoint("localhost", 8080))
      stdout.println(formatCoordinate(10, 20))

      // Numeric addition is unaffected (not String type)
      a <- 1
      b <- 2
      c <- 3
      total <- a + b + c
      stdout.println(`Total: ${total}`)

Common mistakes

E11068 — Concatenating 3 or more string parts with + triggers E11068. Use backtick interpolation which compiles to a single allocation. See ek9 -h E11068 for details.

Incorrect:

<- result as String: "Hello " + name + "!"

Correct:

<- result as String: `Hello ${name}!`

E11068 — Concatenating three or more String parts with '+' triggers E11068 — use backtick interpolation `${host}:${port}`, which compiles to a single allocation. See ek9 -h E11068 for details.

Incorrect:

<- result as String: host + ":" + $port

Correct:

<- result as String: `${host}:${port}`
Other ways to ask this
  • What is error E11068 in EK9?
  • Why can't I use + to build strings in EK9?
  • How do I fix PREFER_STRING_INTERPOLATION error in EK9?

Coming from another language?

Java: no restriction on + chains (StringBuilder optimisation by javac since Java 9, invokedynamic since Java 11). Python: no restriction, but f-strings recommended by PEP 498. Rust: format!() macro preferred over + chains but not enforced. Go: no restriction, but fmt.Sprintf() recommended. JavaScript: template literals recommended over + chains by ESLint prefer-template rule but not a hard error. Kotlin: string templates recommended but + chains compile fine. Swift: string interpolation \\(expr) recommended but + chains compile fine, no enforcement. EK9: 3+ part + chains on String are a hard compiler error (E11068) because EK9 has a bespoke STRING_INTERPOLATION IR instruction that generates provably better code.

Keywords: compiler, debug, plus, text, swift, backtick, compile, PREFER_STRING_INTERPOLATION, E11068, performance, interpolation, concatenation, error, string