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:

  first <- "Hello"
  second <- "World"
  third <- "!"
  stdout.println(first + second + third)                   // E11068: 3 parts
  stdout.println(first + " " + second + " " + third)       // E11068: 5 parts
  stdout.println(second + third + "]")                     // E11068: 3 parts

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})`

Interpolation converts non-String values (an Integer port, a Float x) to text itself, so no $ is needed inside ${...}.

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: performance, E11068, PREFER_STRING_INTERPOLATION, compile, backtick, swift, text, plus, debug, compiler, string, error, concatenation, interpolation