4

In, for example, the Bash scripting language, the following creates a string called $VAR which begins at the first " quote and continues until the next unescaped " quote.

$VAR="
    hello
world!

this string preserves all
    whitespace"

This makes it very easy to write multiline strings without concatentation or a million annoying \ns everywhere, and it makes the parser very easy to write (speaking from experience) because you can just gobble everything between unescaped quotes with a regex like "([^"\\]*(?:\\.[^"\\]*)*)" or so.

Bash is (hopefully!) not a mission-critical or systems-programming language, but it is a systems-scripting language intended for *nx boxes on which everything is text, so perhaps it's apt.

Recall that Bash is written in C, and so this string is (probably) stored as \n\thello\nworld\n etc, but the point is the source written by the programmer (and the above is far more readable).

Many (I daresay C-influenced) "proper" Languages Used For Real Purposes find some unknown problem with allowing strings to contain literal newlines, and thus require one or more of the following:

  • escape sequences\n (which get compiled into \r\n on Windows)

  • special syntax (""" multiline string """ in Py, `multiline string` in Go, or R" raw string literal " in C++11, etc)

  • special functions to write newlines (Forth's CR, for example, although Forth gets a pass because it knows squat about strings)

I do not understand why more languages don't allow strings to be "implicitly" multiline.

Pros:

  • ease of use & practicality, clearer code, etc

  • simpler, more straightforward and thus more maintainable parser (at least, for hand-written ones)

Cons:

  • may make some code less readable, if abused

  • ?

Is there an explicit reason this is the case, or has it just been blindly(?) adopted from C like so many other things? Moreover, if I'm writing a parser or designing a language, is there a compelling argument as to why I should restrict string literals to a single line?

closed as primarily opinion-based by gnat, gbjbaanb, user40980, Robert Harvey, coredump Feb 11 '16 at 18:03

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 5
    Forget a closing quote, then see what happens in various languages. Where will the error message locate the problem? Try to indent a multiline string to match the indentation of your source code. Would the indent be visible inside the resulting string? Or does the long string break your indentation because each line must start in column 1? Also, in C multiple literals are not much of an issue because adjacent string literals are concatenated by the compiler: "a" "b" in the source code is compiled as "ab", which makes it easy to have a large string that is distributed over multiple lines. – amon Feb 11 '16 at 14:45
  • 2
    Every language feature has a cost. Most language features that don't get implemented are omitted because the cost exceeds the benefit. To put it another way, language designers omit features because they decide to do so. Why? You'd have to ask them. – Robert Harvey Feb 11 '16 at 16:27
  • 1
    @cat: The problem with the "solution" to #1 is that it doesn't scale. If you have an unterminated string starting on line 100, and the next string start on line 200, you'll get an error about invalid code inside the second string, or if it's somehow legal code, you'll be told that the string on line 200 was unterminated. Repeat for more strings beyond line 200. The errors get rather unpleasant, and don't obviously identify the original source of the problem. – ShadowRanger Feb 11 '16 at 17:39
  • 1
    Furthermore, your comments on various answers show that you are opinionated in what you are willing to accept: "I don't consider what the Wikipedia entry says are issues, to be issues". This taken as a whole seems to indicate that you are looking for a discussion instead. – user40980 Feb 11 '16 at 19:55
  • 2
    @cat: The point is that it is useful to have two different syntaxes for string literals, one which uses escapes and one without ("raw"). For example raw strings (@"" in C#) are often used for regexes, since the regex language has its own escapes. The question of escaping linebreaks is just one part of this more general distinction. If you couldn't escape linebreaks in strings it would also be really annoying. – JacquesB Feb 13 '16 at 10:42
4

FWIW, Ocaml accepts a limited form of multi-line string literal :

String literals are delimited by " (double quote) characters. The two double quotes enclose a sequence of either characters different from " and \, or escape sequences from the table given above for character literals.

To allow splitting long string literals across lines, the sequence \newline spaces-or-tabs (a backslash at the end of a line followed by any number of spaces and horizontal tabulations at the beginning of the next line) is ignored inside string literals.

and C++11 has raw string literals so you can code:

const char* s1 = R"foo(
Hello
World
)foo";

Hence several languages have some ways to write multi-string literals.

  • That's interesting; I've never really used the ML languages because I think they have ugly, non-finger-friendly syntax but that's interesting. The C++11 thing is just parallel to the """ python """ and `` golang `` special syntax – cat Feb 11 '16 at 15:16
  • The C++11 thing is not parallel to """ ... """ in Python. The main feature of the raw strings in C++11 is that raw strings don't have any escapes in them (like r"..." in Python), not the fact that they're multiline. You couldn't tell this from the answer though... – CoffeeTableEspresso Mar 2 at 2:00
15

What happens when you didn't mean to have a multi-line string, but instead forgot to close the quote?

The parser will chew through the code until it hits another quote in a completely different part of the program, then proceed as normal. This will very likely lead to confusing, unrelated errors since the string is no longer the parse error. At worst, you get a program that compiles properly and does something completely different.

This is compounded by partial-processing of code in modern IDEs. As you're typing the string, you're going to cause this scenario naturally. That will cause the IDE to toss the cached AST since it sees a bunch of stuff has changed, leading to slower intellisense (and similar constructs).

  • 2
    If you forget to close the quote, that's your problem, and you either get a) "Syntax error: found EOF before closing quote at..." or b) another, unrelated quote being interpreted as the end of the string, except that will cause that string to orphan its closing quote and so in the end you get the same SyntaxError, rightly. – cat Feb 11 '16 at 14:49
  • 4
    Modern IDEs are designed for Modern Languages. If Modern Languages used this, or if C had started out with this and thus influenced other languages to have it, then IDEs would be different, so that is a non-issue. – cat Feb 11 '16 at 14:50
  • 21
    Intellisense is for lazy people? If you work on a codebase of reasonable complexity, it's an invaluable tool for remembering exactly what methods are defined on Foo. – Sam Dufel Feb 11 '16 at 14:57
  • 9
    @cat Well now you are starting to seem like a flaming moron. Humans have better things to do than memorize the (sometimes exceedingly numerous) function declarations on any particular class or namespace or what-have-you. If you don't appreciate the benefits of a good IDE such as IntelliJ that eliminates the need to look up documentation in a lot of cases where you don't necessarily need to, then you are wasting valuable time that could be spent being more productive. This is especially true of functions built into SDKs. Sometimes I just want to quickly list all of the methods on String. – Chris Cirefice Feb 11 '16 at 16:46
  • 1
    I don't get the partial processing argument. Would the IDE need to throw away its AST when I type an opening brace that invalidates my program (or changes scope of everything or…) as well? – Bergi Feb 11 '16 at 17:53
-2

The preprocessor has already given meaning to newline characters. You can't completely undo that at a higher level. Compare:

char s1[] = "This is how macros work in C\nExample\n    #define IS_GOOD 1\n";

with

char s2[] = "This is how macros work in C
Example
    #define IS_GOOD 0
";

Clearly the second is easier to read (in a hypothetical C compiler that accepts multiline string literals).

It also doesn't do what you expected. s2 doesn't contain an example of C code at all, what you actually got was:

char s2[] = "This is how macros work in C\nExample\n";

oops.

Or, you can change the preprocessor grammar also, by making it aware of quoting. Then you lose the ability to expand macros to definitions containing quotes. Hardly any better.

Things that cause unexpected and confusing results are not desirable features.

  • 3
    The C preprocessor has given meaning to newlines. I am not talking about forcing the C standard to make strings work in this way; I am not suggesting we should break or change existing languages. That would not make any sense, because the C preprocessor is written for the C language which exists currently. I think you misread the question; never did I suggest implementing this. If C had this sort of string, then the preprocessor would not behave in that way. – cat Feb 11 '16 at 17:28
  • 1
    @cat I also addressed the idea of having the different preprocessor design. Try reading the answer completely before commenting (and voting) – Ben Voigt Feb 11 '16 at 17:58
  • 1
    But you're still only talking about C. I'm not talking about any specific language. – cat Feb 11 '16 at 18:06
-3

I cannot answer on the "why"; as far as I know language designers tend to copy the "bad stuff" as many times as the "good stuff" when designing a language based on other languages.

I do have to say that using RegEx to parse your code is not the best way to do it and writing a parser which can keep track of multiline strings might be harder than you would expect it to be especially if indentation is part of the language.

What I can say about designing a new string format is to not even use the double quote ". If I were to design a language I would use parentheses to encapsulate "content" and implement a function in the standard library like so:

let foo = String(This is my string which can be multiline and does not
                 need escape characters for anything other than \( and \).)
  • 1
    No, the regex is just a part of the parser, I am not parsing with regex. The regex exists to make handling string literals easier than without it. – cat Feb 11 '16 at 15:14
  • 5
    How are ( and ) in your fictional language different from " in a normal language? – Bergi Feb 11 '16 at 17:55
  • @Bergi Makes nesting a heck of a lot easier if done wisely. The example here really shouldn't need the backslash escapes. Only an unpaired ) should need to be escaped. – 8bittree Feb 12 '16 at 18:00

Not the answer you're looking for? Browse other questions tagged or ask your own question.