Problem:
Having had to include some JavaScript, XML and HTML inside of my Clojure code here and there, it can be pretty annoying and error prone to have to escape quotes. This holds true as well when scripting, and running shell command, you can get into hairy escaping scenarios.
Solution:
Add a string literal which can be adapted to contain any sort of string without the need for escaping.
Suggestions:
Text blocks
Some other languages offer something called a text block where you can write a string using triple or more quotes, where all characters are then allowed:
(println """
This " is allowed,
and no need to escape it.
"""
Text blocks often come with additional features, such that the first and last newline isn't part of the string. And the position of the triple quote in the source code delineate the beginning of the lines in the quote. Thus the above code prints:
This " is allowed,
and no need to escape it.
and not:
This " is allowed,
and no need to escape it.
While text blocks are neat visually, as they have nice alignment in the source code. They are whitespace dependent, and Clojure up to now is a whitespace independent language, meaning whitespace does not matter. I think it would be best to keep it that way. Thus the next two suggestions.
Raw strings
Sometimes the text block without the "block" features is known as a raw string literal:
(println """This " is allowed,
and no need to escape it.
Also support multi-line, but
not the "block" style of text blocks.""")
Thus:
(println """
This " is allowed,
and no need to escape it.
"""
Prints:
This " is allowed,
and no need to escape it.
Unlike for Text Blocks.
If you need a triple quote, just make the delimiter a quadruple quote:
""""This """ is now allowed as well.""""
The issue with raw string is that, if you use say double quotes as your delimiter:
""This is a raw " string!""
But want your single quote to be at the beginning or the end:
"""{{hello}}"""
I want the string: "{{hello}}"
, not {{hello}}
, but the raw string can not disambiguate the two, as now it thinks this is a triple quoted delimiter.
One solution is to allow an escaped quote only at the beginning or end:
""\"{{hello}}\"""
But not in the middle:
""\"{{he\llo}}\"""
This is the string: "{{he\llo}}"
So the escape character \
can appear anywhere except at the beginning if followed by a quote, and at the end if followed by a quote.
I still don't find this ideal. There's too many rules, and there are still cases where an escape is required.
Unescaped string (my favorite)
The idea here is to allow any string to be used as the delimiter. Thus given whatever possible string we want to nest inside our Clojure code, we can always find a string which is not contained in it to use as our delimiter.
Lets say the reader macro #text is added. Which expects the following form to be a regular string which tells it the delimiter for the following form to read:
(println #text "|" |"{{hello}}"|)
Would print:
"{{hello}}"
The first arg to #text tells it what the delimiter for the following raw string should be. That way, you absolutely never need an escape sequence inside the raw string. For any given string, you can find a delimiter string not contained in it to handle it properly.
A crazy thought I had with this approach, just trowing it out there, is if you use a sufficiently random string as the delimiter, could be a weird way to protect against forms of injection:
(println #text "xIBgdSl4TCCOIdqdMu9G" xIBgdSl4TCCOIdqdMu9G
Can't nobody guess the delimiter to escape the string context :p
xIBgdSl4TCCOIdqdMu9G)
Thank You