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