How do I escape characters in EK9 string interpolation?

← Getting Started · Ref: Q43

EK9 has two string types with different escaping rules. Double-quoted strings are plain text where $ is just a regular character. Backtick strings support interpolation where ${...} evaluates expressions. This means backtick strings need special escaping for $ and backtick characters that double-quoted strings do not.

BACKTICK STRING ESCAPING (interpolation strings)
Backtick strings evaluate ${...} expressions. To include literal special characters:

  \$    Literal dollar sign (prevents interpolation trigger)
  \`    Literal backtick character
  \t    Tab
    Newline
  \\    Literal backslash
  \uXXXX  Unicode code point

Examples:

  salary <- 42000
  stdout.println(`Your salary is \$${salary}`)
  //Output: Your salary is $42000
  stdout.println(`Use \`backticks\` for interpolation`)
  //Output: Use `backticks` for interpolation

DOUBLE-QUOTED STRING ESCAPING (plain text)
Double-quoted strings have NO interpolation, so $ is just a regular character:

  plainDollar <- "Price: $42"
  //Output: Price: $42
  withQuote <- "She said \"hello\""
  //Output: She said "hello"
  withBackslash <- "C:\\Users\\file.txt"
  //Output: C:\Users\file.txt

WHY THIS MATTERS FOR EK9 OPERATORS

EK9 uses $ in three operator contexts:

  $value     to-string conversion
  $$record   to-JSON serialization
  $?.path    data navigation path literal

When you want to MENTION these operators as text in an interpolated string, you must escape the dollar sign:

  name <- "EK9"
  stringRep <- $name
  stdout.println(`\$ converts to string: ${stringRep}`)
  me <- PersonDetail(name: "Steve", age: 30)
  jsonRep <- $$me
  stdout.println(`\$\$ converts to JSON: ${jsonRep}`)
  navPath <- $?.store.book[0].title
  stdout.println(`\$? creates a path: ${navPath}`)

Without the backslash, the lexer would try to parse $$ or $? as operators inside the string, causing parse errors.

USING OPERATORS DIRECTLY INSIDE INTERPOLATION

You can use $ and $$ operators directly inside ${...} without an intermediate variable:

  stdout.println(`Direct JSON: ${$$me}`)
  stdout.println(`Direct to-string: ${$salary}`)

The ${$$me} pattern evaluates $$me (to-JSON) and interpolates the result. The ${$salary} pattern evaluates $salary (to-string) and interpolates. This is concise and avoids creating temporary variables just for display.

COMBINING ESCAPED AND INTERPOLATED CONTENT

You can mix escaped dollar signs and interpolation in the same string:

  price <- 9.99
  stdout.println(`Item costs \$${price} (tax not included)`)
  //Output: Item costs $9.99 (tax not included)

The \$ produces a literal dollar sign, then ${price} is the interpolation expression. The lexer processes them left to right: backslash-dollar is a literal, dollar-brace is interpolation.

BACKSLASH-SPACE SHORTCUT

If a backslash is followed by a space, it is treated as just a backslash. This is a convenient alternative to \\ when the backslash is not immediately before a special character:

  withBs <- "path\ here"
  //Output: path\ here

QUICK REFERENCE TABLE

  Escape    Double-quoted    Backtick
  \$        not needed       REQUIRED (prevents interpolation)
  \`        not needed       REQUIRED (prevents string end)
  \"        REQUIRED         not needed
  \t        tab              tab
        newline           newline
  \\        backslash        backslash
  \uXXXX   unicode          unicode

The key insight: double-quoted strings need \" for quotes, backtick strings need \$ for dollars and \` for backticks. Each string type only needs escaping for its own delimiter and trigger characters.

See Q37 (How do I work with strings in EK9?) for string methods, streaming, and interpolation basics. See Q42 (How does the Path type work?) for the $? operator that often needs escaping in interpolated output. See Q113 for the text construct for internationalization.

Use 'ek9 -h String' to see the full String API. See Q188 for JSON as first-class type and the $$ operator. See Q242 for conversion operators ($, $$, #?) used in interpolation.

Example

defines module qa.escape.interpolation

  defines record
    PersonDetail
      name <- String()
      age <- Integer()

      default PersonDetail()

      PersonDetail()
        ->
          name as String
          age as Integer
        this.name :=: name
        this.age :=: age

      default operator $$

      default operator ?

  defines program
    EscapingDemo()
      stdout <- Stdout()

      // === BACKTICK-SPECIFIC ESCAPING ===

      // \$ produces a literal dollar sign in backtick strings
      salary <- 42000
      stdout.println(`Your salary is \$${salary}`)

      // Show the $ operator label without triggering interpolation
      name <- "EK9"
      stringRep <- $name
      stdout.println(`\$ converts to string: ${stringRep}`)

      // Show the $$ operator label
      me <- PersonDetail(name: "Steve", age: 30)
      jsonRep <- $$me
      stdout.println(`\$\$ converts to JSON: ${jsonRep}`)

      // Show the $? path literal label
      navPath <- $?.store.book[0].title
      stdout.println(`\$? creates a path: ${navPath}`)

      // \` produces a literal backtick inside a backtick string
      stdout.println(`Use \`backticks\` for interpolation`)

      // === DOUBLE-QUOTED STRING ESCAPING ===

      // In double-quoted strings, $ is just a regular character
      plainDollar <- "Price: $42"
      stdout.println(plainDollar)

      // \" for literal quote in double-quoted strings
      withQuote <- "She said \"hello\""
      stdout.println(withQuote)

      // \\ for literal backslash
      withBackslash <- "C:\\Users\\file.txt"
      stdout.println(withBackslash)

      // === COMMON ESCAPE SEQUENCES (both string types) ===

      // \t tab, \n newline
      withTab <- `Column1\tColumn2`
      stdout.println(withTab)

      withNewline <- "Line1\nLine2"
      stdout.println(withNewline)

      // \uXXXX for Unicode code points
      copyright <- "\u00A9 2024"
      stdout.println(copyright)

      // Backslash followed by space is just a backslash
      withBs <- "path\ here"
      stdout.println(withBs)

      // === OPERATORS DIRECTLY IN INTERPOLATION ===

      // Use $$ directly inside ${...} — no intermediate variable needed
      stdout.println(`Direct JSON: ${$$me}`)

      // Use $ directly inside ${...}
      stdout.println(`Direct to-string: ${$salary}`)

      // === COMBINING ESCAPING WITH INTERPOLATION ===

      // Mix escaped dollar signs and interpolation in the same string
      price <- 9.99
      stdout.println(`Item costs \$${price} (tax not included)`)

      // Multiple interpolations with escaped operators
      x <- 42
      stdout.println(`Integer ${x}, use \$ for to-string, \$\$ for to-JSON`)

Common mistakes

E08180 — Record fields must be initialised at declaration. Declaring fields without initialisation triggers E08180. Use inline initialisation like 'String()' to create an unset-but-initialised field. See ek9 -h E08180 for details.

Incorrect:

name as String
      age as Integer

Correct:

name <- String()
      age <- Integer()
Other ways to ask this
  • How do I include a literal dollar sign in a backtick string in EK9?
  • What is the difference between escaping in double-quoted and backtick strings in EK9?
  • How do I display the $ and $$ operators as text in interpolated strings in EK9?
  • Why does my backtick string fail when I use $ without interpolation in EK9?

Coming from another language?

Java: no string interpolation until Java 21 string templates (preview), $ is a regular character in all strings, escape sequences same as EK9 double-quoted strings. Python: f-strings use {expr} for interpolation, literal brace needs {{ doubling not backslash escaping, $ is a regular character. JavaScript: template literals use ${expr} in backticks, literal backtick needs backslash escaping, literal dollar-brace needs \${ or ${'$'}, very similar rules to EK9 backtick strings. Kotlin: string templates use $var and ${expr}, literal dollar needs ${'$'} trick (no backslash escape), a common pain point. Ruby: string interpolation uses #{expr} in double-quoted strings, $ is a regular character but #{ needs escaping. C#: interpolated strings use $"...{expr}..." and literal brace needs {{ doubling. EK9: backtick strings use ${expr}, \$ for literal dollar, \` for literal backtick, double-quoted strings are plain text where $ needs no escaping. The backslash-dollar approach is more intuitive than Python's brace doubling or Kotlin's ${'$'} workaround.

Keywords: unicode, quote, beginner, escape, intro, backslash, backtick, dollar, start, operator, interpolation, literal, string, first