This week's build of Elements 12, build .3047, introduces a major new feature for the Oxygene language: Raw Strings. Raw strings are a new way of declaring string literals that make it easier to define more complex strings without worrying about escaping things such as quotes or curly braces.

Raw strings can come in two forms that behave similarly in most ways: single-line raw strings and multi-line raw strings. Any raw string literal starts with one or more hash symbols (#) followed by one or more double quote symbols ("), and all raw strings support interpolation with curly braces ({).

Single-line Raw Strings

A single-line raw string starts with the opening sequence (#" or a variation thereof), is followed by one or more non-quote characters, and then terminated by the same number of quotes that started it. Inside the literal, quote (and hash) characters can be used at will, as long as they are fewer than the quotes in the opening sequence, and they are not the first or last character:

var x := #""He said, "Hodwy!"."";

In the above example, the opening sequence has two quote marks after the hash: #"". This means the string will continue until another set of two quotes is encountered. Using single quotes inside the literal, like around the "Howdy", is fine, and they do not need to be escaped.

This works for any (reasonable) number of quotes:

var y := #"""""Want four quotes? why not!"""". It's fine!""""";

Note: For ambiguity reasons, a single-line raw string cannot be empty, as it would be impossible to tell whether it's just starting, or done. But then, an empty raw string is pointless – just drop the # and make it a regular string literal ;).

A single-line raw string must be terminated on the same line that started it (duh! 🙃).

Multi-line Raw Strings

A multi-line raw string starts with the same opening sequence (#" or a variation thereof), immediately followed by a linebreak. No non-whitespace characters may follow on the same line, not even comments (comments inside a string aren't comments, anyways ;).

The actual content of the string literal will start on the next line, and may continue across as many lines as needed to express the string you need.

The closing sequence – the same number of quites that started it – must follow on its own new line, preceded by nothing but whitespace:

var z := #""
         As the water flows over the bridge
         As we walk on the floodland
         As we walk on the water
         We forget
         We forget
         Rain from heaven 
           - The Sisterhood, "Rain from Heaven"
         "";

As before, the number of quotes in the opening sequence determines how many quotes are needed to terminate the string (here, two, therefore, the individual quotes on the last line are accepted as part of the string).

Multi-line raw strings have one additional special behavior, and that is the trimming of leading whitespace. The compiler will look at the number of spaces (tabs count as two spaces) in front of the closing quotes ("";), and remove the same number of leading spaces from the beginning of every line in the string.

As a result, even though the string is indented in code to match its surrounding – loosely suggested by the length of the var z := – the lines of the lyrics will have no indentation in the final string, and the last line of attribution will have only two spaces of indent.

This means you no longer need to have your multi-line strings stick oddly to the left edge of your code, defying the indentation of its surrounding code.

Note: All lines of the string must be indented at least as much as the closing quotes. If a line "sticks out" to the left, the compiler will emit an error.

Also note that the string literal shown above does not include a leading or trailing line break. It starts with A and ends with ". Of course, empty lines can be added at the start or the end of the literal, to add additional linebreaks. The string literal will also not include any trailing whitespace on any line.

Interpolation in Raw Strings

All raw strings support interpolation, similar to the existing interpolated strings starting with $" that Oxygene has supported for a while.

Just like the number of starting quotes indicates how many quotes end the string, the number of hashes (#) indicates how many curly braces ({/}) are used for interpolation:

var a := #"It's {time} o'clock.";

In its simplest form, a single curly starts and ends interpolation, just as you're used to from classic interpolated strings. In fact (with a couple of small caveats noted below), you can probably change most of your interpolated strings over to raw strings, just by replacing the $ with a #.

What if you want literal curly braces in your string... literal? No problem, just use more than one # in the opening sequence, and you can have as many as one fewer consecutive curly braces in your string, anywhere. Need some inline Json, for example? easy:

var j := ##""
         { 
           "Title": "IT", 
           "Author": Stephen King",
           "Published": 1984
         }
         "";

Need more than one? Also no problem:

var k := ###""{{Hello in double curlies, {{{lName}}}}}"";

Here, the double curlies at the start are kept literally, but the triple curlies near the end will treat lName as interpolated code.

If a literal contains more consecutive curly braces than needed to start an interpolation, the additional curly braces are kept literally:

var l := ##"keep a curly here: {{{5+3}}}"; // "keep a curly here: {8}"

Note: as mentioned before, there are a couple of small behavioral differences between interpolated raw strings. These are especially important to keep in mind if you are changing your $" strings to #" for consistency:

In classic $" interpolated strings, two {{ would be used to "escape" the interpolation. Raw strings do not do escaping like that, so you'd want to use  ##" instead, to have single-curlies in your literal without the need to escape them:

var x := $"{{keep one curly}"
// equals:
var x := ##"{keep one curly}"

Also, classic $" interpolated strings (and non-interpolated strings with double quotes) may contain linebreaks at any point, and will preserve all leading whitespace. Raw strings, as outlined above, will not, and must start on a fresh line, if they are multi-line:

var x := $"this
 is fine";
// equals:
var x := #"
         this
          is fine
         ";

Editor Support

The code editor in Fire and Water has been updated to visually highlight (or rather, lowlight) the curly braces "swallowed" by the interpolation. Especially when you're surrounding interpolations with additional curlies, this is a helpful visual aide:

Also: Delphi Multi-line Strings

It's worth mentioning here that a short while ago we also added support for Delphi's new multi-line string syntax, for compatibility purposes. Delphi multi-line strings start with an odd number of three or more single quotes ('), and end with the same amount. Similar to Oxygene's (and C#'s) raw strings, they too require the content of the literal to start on a new line, have the closing sequence on a new line, and will remove any leading whitespace. They do not support interpolating.

var d := '''
   Delphi's multi-line
   string syntax 
   is supported too
   ''';

Get Elements .3047 Now.

Elements build .3047 – with the new Raw Strings on Oxygene and much more is available on the Stable channel now, as free update for all customers, and as free trial download for new users.

Enjoy!