<p>One option in Python is the f-string:</p>
<pre class="lang-python prettyprint-override"><code>f&quot;{a} {b} {c}&quot;
</code></pre>
<p>Which is equivalent to:</p>
<pre class="lang-python prettyprint-override"><code>str(a) + &quot; &quot; + str(b) + &quot; &quot; + str(c)
</code></pre>
<p>What are some other options for formatted string literals, and what are their advantages and disadvantages?</p>

<syntax><strings><string-interpolation>
What are the different syntax options for formatted string literals?
<h1>Swift Style</h1>
<pre class="lang-swift prettyprint-override"><code>&quot;\(a) \(b) \(c)&quot;

&quot;&quot;&quot;
&lt;body&gt;
    &lt;p&gt;\(hello_world_str)&lt;/p&gt;
&lt;/body&gt;
&quot;&quot;&quot;
</code></pre>
<p>This syntax is reasonably lightweight and doesn't conflict with the common unformatted string syntax (many languages that use backslash as a string escape symbol will not allow unrecognized escape sequences like <code>\(</code>, and such occurrences regardless are far less common than the literal string characters <code>{</code> and <code>}</code>).</p>

CC BY-SA 4.0
2023-05-20T11:15:39.017Z
2023-05-20T11:15:39.017Z
Olive
CC BY-SA 4.0
2023-05-20T12:56:31.903Z
Worth noting that it's possible to add custom overloads of this: https://languagedesign.stackexchange.com/a/249/15
Bbrk24
<p>I would like to talk about the old FORTRAN formats at least from historical respect:</p>
<pre><code>      WRITE (6,7000) month
      WRITE (6,7000) day

7000  FORMAT(15H Hello, world:  , I3)
      END
</code></pre>
<p>Why largely obsolete now, they include some interesting features:</p>
<ul>
<li>The formatting string (number formats and surrounding text) is defined separately from the statement that prints the values. It can be far apart (it was common to have them at the end of the program). This reduces the &quot;visual noise&quot;.</li>
<li>The formatting string is referenced by the label, 7000 in this example (6 is the output channel, the terminal) and can be shared by multiple print (write) statements. If the same or related values are printed, the format only needs to be defined once.</li>
<li>All printable characters can be used in the message without any escaping, providing the length of the text (15 characters) instead. While it is very error prone to count and adjust these counters, reading is easy.</li>
<li>I3 is the number format (integer, field width of 3). You can read <a href="https://help.perforce.com/pv-wave/12.0/PVWAVE_Online_Help/pvwave.html#page/Foundation%2Fap.a.format.066.09.html%23ww423257" rel="nofollow noreferrer">here</a> about the possible format specifiers.</li>
</ul>

CC BY-SA 4.0
2023-07-12T12:25:03.130Z
2023-07-12T12:30:05.950Z
2023-07-12T12:30:05.950Z
Audrius Meškauskas
CC BY-SA 4.0
2023-11-05T20:22:25.793Z
An advantage of this approach is that it facilitates the use of code generation tools to generate bespoke code which handles formatting.  When using something like `printf`, there's often no way for an implementation to include only the features that a program actually uses, but the needs of bespoke formatting functions could be determine statically.
supercat
<h2>No built-in syntax</h2>
<p>If your language either supports procedural macros or allows dynamically accessing variables by name, you can avoid having special syntax for formatted strings at all and instead implement them as a macro/function in the standard library or even an installable package.</p>
<p>An example of the macro approach: Nim's <a href="https://nim-lang.org/docs/strformat.html" rel="nofollow noreferrer"><code>std/strformat</code></a></p>
<p>An example of the reflection approach: Arturo's <a href="https://arturo-lang.io/documentation/library/strings/render/" rel="nofollow noreferrer"><code>render</code></a></p>

CC BY-SA 4.0
2023-07-13T09:48:02.183Z
2023-07-13T09:48:02.183Z
xigoi
<p>A lot of examples of format string literals have already been given. I'll just mention two issues here:</p>
<h1>Internationalization (i18n)</h1>
<p>As mentioned by Ray Butterworth:</p>
<blockquote>
<p>In python one can say:</p>
<pre><code>gimme['en'] = f&quot;Give me the {colour} {object}.&quot;
gimme['fr'] = f&quot;Donnez moi {definite_article(object)} {object} {colour}.&quot;
</code></pre>
</blockquote>
<p>The problem here is that this only works when declaring all the translations in the code. You can't load f-strings from a file, unless you use <code>eval()</code>, which then opens you up to lots of security issues.</p>
<p>Separating code from translations is very important if you want to outsource translating your code to a team of people that are not coders. For example, with <a href="https://en.wikipedia.org/wiki/Gettext" rel="nofollow noreferrer">GNU gettext</a>, a file can be created by a tool containing all the original format strings in your code, and then translaters can make a translation file for all those strings for their language. That file containing translations can be loaded at runtime, no recompilation necessary.</p>
<p>Another issue with the Python example from Ray is that it's very slow if you have translations for lots of languages: each format string literal is evaluated as it is added to the dict <code>gimme</code>, even if you are only ever going to use one of them. And you cannot move the format string literals out of the function you are using them if it references local variables.</p>
<h1>Equivalence</h1>
<p>You mention:</p>
<blockquote>
<pre><code>f&quot;{a} {b} {c}&quot;
</code></pre>
<p>Which is equivalent to:</p>
<pre><code>str(a) + &quot; &quot; + str(b) + &quot; &quot; + str(c)
</code></pre>
</blockquote>
<p>Being able to specify how a format string literal is interpreted and what it is equivalent to is great. You can then think of doing that in other languages as well, not just interpreted ones! Wouldn't it be interesting if this could be applied to C++? What if:</p>
<pre><code>std::cout &lt;&lt; f&quot;Hello {name}, the answer is {6 * 7}!\n&quot;;
</code></pre>
<p>Was defined to be equivalent to:</p>
<pre><code>std::cout &lt;&lt; std::format(&quot;Hello {}, the answer is {}!\n&quot;, name, 6 * 7);
</code></pre>
<p>It's a relatively easy change to the language, and makes use of existing library features to do the heavy lifting. Even better would be to allow the formatting function to be used to be replaced by a custom version (just like <code>new</code> can be replaced by a user-defined function in C++). This would open up new possibilities, for example automatically applying <code>gettext()</code> on the format string to internationalize your program with very little changes.</p>

CC BY-SA 4.0
2023-07-12T14:48:29.600Z
2023-07-12T14:48:29.600Z
G. Sliepen
CC BY-SA 4.0
2023-07-13T11:31:55.180Z
Hm, `operator f""(const char* str, std::size_t size, auto&&... args)`? Or if C++ had reflection like in @xigoi's answer, maybe you'd only need C++11's user defined literals.
G. Sliepen
<h1>RegEx style (similar to shell)</h1>
<h3>I’ll just use PCRE2 regex for this example.</h3>
<br>
<p>Match expression (to get input since formatting values are stored in capture groups): <code>(.*)\n(\d*)</code></p>
<p>Substitution expression (format string): <code>My name is $1 and I am $2 years old.</code></p>
<p><a href="https://regex101.com/library/bmex4E" rel="nofollow noreferrer">Try it online!</a></p>

CC BY-SA 4.0
2023-07-13T11:03:10.767Z
2023-07-13T11:03:10.767Z
The Empty String Photographer
CC BY-SA 4.0
2023-07-13T11:33:08.933Z
How does this answer the question?
mousetail 'he-him'
CC BY-SA 4.0
2023-07-13T11:34:35.060Z
@mousetail It's a way of formatting
The Empty String Photographer
CC BY-SA 4.0
2023-07-13T11:35:10.967Z
This question is about syntax options for formatting
mousetail 'he-him'
<p>Go offers excellent support for string formatting in the printf tradition. So, based on the formatter (%v, %t, %d,%s, etc.) it can handle different types of parameters and print the result as a string.
<a href="https://gobyexample.com/string-formatting" rel="nofollow noreferrer">https://gobyexample.com/string-formatting</a></p>

CC BY-SA 4.0
2023-05-20T11:12:11.943Z
2023-05-20T11:12:11.943Z
user514
CC BY-SA 4.0
2023-05-20T11:21:19.830Z
OP is specifically asking about formatted string literals (such as Python's f-strings), rather than string formatting in general (such as Python's `str.format`).
Olive
CC BY-SA 4.0
2023-05-21T15:24:03.223Z
f-strings is the better replacement of python's previous both %-formatting and str.format()
user514
<h1>Shell style</h1>
<p>Like in shell:</p>
<pre class="lang-sh prettyprint-override"><code>&quot;hello, $name&quot;
</code></pre>
<p><code>name</code> is a variable.</p>

CC BY-SA 4.0
2023-06-10T08:35:46.457Z
2023-06-10T08:35:46.457Z
чистов_n
<h1>Kotlin Style</h1>
<p>Kotlin has pretty similar string interpolation to Python. The difference is that you don't need to specify a special f-string with an 'f' before the string but do need to specify the interpolation with a '$'.</p>
<p>As an example from the <a href="https://kotlinlang.org/docs/java-to-kotlin-idioms-strings.html#concatenate-strings" rel="nofollow noreferrer">Kotlin docs</a>:</p>
<pre class="lang-kotlin prettyprint-override"><code>val name = &quot;Joe&quot;
println(&quot;Hello, $name&quot;)
println(&quot;Your name is ${name.length} characters long&quot;)
</code></pre>
<p>This looks neater as you don't need the {} braces around every expression, but you can include them for longer expressions. You also don't need to specify that it is an f-string before using the interpolation.</p>

CC BY-SA 4.0
2023-05-20T11:38:20.307Z
2023-05-20T11:38:20.307Z
FireTheLost
CC BY-SA 4.0
2023-07-12T23:18:47.597Z
This, or something like it, is also used in Perl IIRC.
Karl Knechtel
<p>Warning: without any ill-intent, this answer post responds to the question by asking more questions (hopefully useful ones, and hopefully while imparting some useful information or insight).</p>
<p>To start with, it's hard to say whether a particular choice or example will be an advantage or a disadvantage just by looking at a string formatting mechanism in isolation. It will really depend on a mixture of what the goals of your language are (Ex. with respect to mechanics or syntax), and following up on that, how the language works as a whole (Ex. with respect to how it is read and run by a machine), and in some cases, decisions you make that ultimately boil down to arbitrary or personal choices (Ex. with respect to syntax).</p>
<p>For example,</p>
<ul>
<li><p>Is it a goal of your language to have familiar syntax to people who program in existing, well-established languages targeting the same or similar problem/application-domains?</p>
</li>
<li><p>Is it a goal of your language to help people who write and solve problems using non-programming languages (Ex. Mathematical notation)?</p>
</li>
<li><p>Is it a goal of your language to provide some definition of &quot;sane basic defaults&quot; / batteries included, or instead to back off and let your users build their own abstractions and tools using the language? (In a sense- variations of opinionation)</p>
</li>
<li><p>Is it a goal of your language to be syntactically rich, or syntactically simple? Both those higher-level directions have valid advantages and disadvantages themselves.</p>
</li>
</ul>
<p>Do you see how it can be really hard for me to point at a syntactic choice a language made, separate it from the context of the language's goals, and then say &quot;this is better in general because &lt;X&gt;&quot;? It would really only make sense for me to say &quot;this made sense to the developers of this language because they wanted their language to achieve its goals, which included &lt;X&gt;&quot;.</p>
<hr />
<p>Broadly speaking (unless the designers of the language didn't care, or weren't given the time to care deeply or design carefully), those kinds of higher design goals are what inform the more concrete choices that are more easily observable at a surface glance.</p>
<p>For example,</p>
<ul>
<li><p>How &quot;deeply&quot; is the mechanism ingrained into the language? (whether it has dedicated syntax / syntactic sugar, or doesn't have any particular special syntax and is really just something implemented <em>using</em> the language and lives at the library level of things. Or a mixture).</p>
</li>
<li><p>How much room does the mechanism provide for users of it to customize it based on their user-defined data structures?</p>
</li>
<li><p>What impact does the implementation have on costs in terms of space and time? If you lean to either end of the spectrum of library vs specialized-syntax, what limitations might you encounter due to the way your runtime and object formats (Ex. machine code, bytecode, interpreted script) work?</p>
</li>
<li><p>Are there degrees of self-consistencies in syntactic choices with other related features in the language?</p>
</li>
<li><p>What tradeoff is made between brevity and intuitiveness of mechanics (related to readability)?</p>
</li>
</ul>
<hr />
<p>The goal of this &quot;big-list&quot; answer post is not really to go very in-depth with how each of these languages work (because that's quite broad, hard for to do with my limited knowledge, and you might get bored), but to try to give you an idea that while there are broad categories we can box things into, the world is a bit wider and more colourful than it might seem from a surface glance, and to give you some ideas of what else there is to think about underneath the level of just syntax. Syntax is just an interface for all of what your language really is when you look beneath that surface, and I assume that's the meat we really care to get at.</p>
<hr />
<p>I'll group what I know based on a more superficial(?) level of how the literals and values to format are arranged positionally at the source level, and order entries of the group very roughly based on what I know about how they fall on the compiled vs. interpreted spectrum (I'm human and I make mistakes. Corrections are welcome).</p>
<ul>
<li><p>There's a style where the &quot;string literal&quot; contains placeholders / slots that describe how to format what fills the placeholder / slot, and then the values that fill the slots are written separately. If I understand correctly, these mostly fall towards the &quot;library-level&quot; end of the spectrum. Ex.</p>
<ul>
<li><a href="https://en.cppreference.com/w/c/io/fprintf" rel="noreferrer">C style <code>printf</code></a></li>
<li><a href="https://en.cppreference.com/w/cpp/utility/format/format" rel="noreferrer">C++23's <code>std::format</code></a> (see also <a href="https://fmt.dev/latest/api.html" rel="noreferrer">the <code>fmt</code> library</a>)</li>
<li><a href="https://pkg.go.dev/fmt" rel="noreferrer">Go's <code>fmt</code> package</a></li>
<li><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Formatter.html" rel="noreferrer">Java's <code>Formatter</code></a></li>
<li><a href="https://learn.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting" rel="noreferrer">.NET's composite format strings</a></li>
<li><a href="https://docs.python.org/3/library/stdtypes.html#str.format" rel="noreferrer">Python's <code>str.format</code></a></li>
</ul>
</li>
<li><p>There's a style where the values to format are / can be positionally arranged at the source level inside the &quot;string literal&quot;. If I understand correctly, these mostly fall toward the &quot;syntax-level&quot; / &quot;language foundational mechanisms&quot; end of the spectrum. Ex.</p>
<ul>
<li><p><a href="https://docs.julialang.org/en/v1/manual/strings/#string-interpolation" rel="noreferrer">Julia's string interpolation</a></p>
</li>
<li><p><a href="https://openjdk.org/jeps/430" rel="noreferrer">Java's string templates (JEP 430)</a></p>
</li>
<li><p><a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated" rel="noreferrer">C#'s interpolated format strings</a></p>
</li>
<li><p><a href="https://kotlinlang.org/docs/java-to-kotlin-idioms-strings.html#concatenate-strings" rel="noreferrer">Kotlin's string &quot;concatenation&quot; / interpolation</a></p>
</li>
<li><p><a href="https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals" rel="noreferrer">Python's formatted string literals</a></p>
</li>
<li><p><a href="https://api.dart.dev/stable/3.0.1/dart-core/String-class.html" rel="noreferrer">Dart's string interpolation</a></p>
</li>
<li><p><a href="https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-template-literals" rel="noreferrer">JavaScript's template literals</a></p>
</li>
<li><p><a href="https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html" rel="noreferrer">Bash parameter expansion</a> and <a href="https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html" rel="noreferrer">command substitution</a></p>
<p>And similar in other shells. Ex.</p>
<ul>
<li><a href="https://fishshell.com/docs/current/language.html#expand-variable" rel="noreferrer">Fish's variable substitution</a></li>
</ul>
</li>
<li><p><a href="https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#variable-references" rel="noreferrer">CMake variable references</a></p>
</li>
<li><p>There's more to see if you just look at <a href="https://en.wikipedia.org/wiki/String_interpolation" rel="noreferrer">Wikipedia's String Interpolation page</a>.</p>
</li>
</ul>
</li>
<li><p>And then there are the approaches that don't use &quot;string literals&quot; at all but still are still designed for formatted text:</p>
<ul>
<li>C++'s streams: <a href="https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2" rel="noreferrer"><code>operator&lt;&lt;</code></a>, <a href="https://en.cppreference.com/w/cpp/header/iomanip" rel="noreferrer"><code>&lt;iomanip&gt;</code></a></li>
<li>(technically speaking,) Java's <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuilder.html" rel="noreferrer"><code>StringBuilder</code></a>  + <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html#toString()" rel="noreferrer"><code>Object::toString</code></a></li>
</ul>
</li>
</ul>
<hr />
<p>From my (potentially faulty or misguided) observation, looking at a lot of the forms of syntax-level approaches that are commonly used, I see that there's nothing really about the part of the syntax related to the interpolation itself in those forms that really limits the user from putting arbitrary expressions there except for the limitations of what expressions can be written in any other expression-fitting part of the language's grammar. Which brings me back to my point on looking deeper and more holistically than just a single syntactic choice for a single mechanism in isolation.</p>
<hr />
<p>Here's something that might go unforgotten, but shouldn't: How capable is your language of evolving with respect to particular syntactic choices here? <em>Does your language care about evolving?</em> Because if it does, since we can't see into the future and what programming paradigms may come, and it may be difficult to see what pain points might be found from experience with writing in the language at larger scales, it would be wise to think about this. This is part of why people who design messaging protocols leave reserved bits, or allow their messaging formats for arbitrary extension. Have you allowed for that kind of room for evolution? Or have you boxed yourself out of that? Or boxed yourself out of forms of evolution that could be more ideal for your goals?</p>
<p>And don't just think about your <em>language</em>. Think about the <em>code</em> that <em>users</em> of your language will write. How could your design choices make it easier or harder for them to evolve <em>their code</em> if your <em>language</em> evolves?</p>
<p>These questions really matter. Look back at the list above. Do you notice that some languages have multiple approaches? And in a number of those cases, those options did not all come into being at the same time? Some languages even might <em>want</em> to take multiple approaches, but doing so would cause old code to take on different meaning (dialect bifurcation (think Python 2 and Python 3)).</p>
<hr />
<p>Lastly, unsolicited, I invite you to take a step back and also ask yourself another question.</p>
<p>Look at your language in a more holistic sense. Aside from any dedicated syntax, dedicated syntactic sugar, or dedicated library things you've decided to provide, in what ways / to what degree does the rest of your language enable its users to devise their own mechanisms for doing what <em>can't be done</em> with what your language gifts them in a neat box wrapped up and tied with a string (pun not intended)? Try using your language to do what it doesn't provide out of the box. Does what you write hold up to the goals of your language? (Ex. (potentially) readability and maintainability)</p>

CC BY-SA 4.0
2023-05-21T08:12:36.487Z
2023-05-21T08:12:36.487Z
starball
CC BY-SA 4.0
2023-05-21T08:19:06.167Z
note to self: TODO: add some rust (the language) info. I forgot, and right now, I need to take a rest.
starball
CC BY-SA 4.0
2023-05-21T10:23:16.707Z
meta note: in an effort to generalize my thoughts here, since there are so many questions like the one here, I've factored some of the "core"out and put it [here](https://languagedesign.stackexchange.com/a/889/251)
starball
CC BY-SA 4.0
2023-06-10T13:52:03.470Z
Another factor is i18n, where word order in messages can be different. In C, having a format string for each language doesn't work. In python one can say: `gimme['en'] = f"Give me the {colour} {object}."`
`gimme['fr'] = f"Donnez moi {definite_article(object)} {object} {colour}."`. Yes, it would be more complicated than that, but it makes the process easier.
Ray Butterworth
CC BY-SA 4.0
2023-06-10T15:25:46.333Z
Can’t you say `%2$s %1$s` to reverse the order in C? I know at least Java supports something like that.
Bbrk24
CC BY-SA 4.0
2023-06-10T20:42:03.657Z
@RayButterworth how does it not work? I fail to see. Your Python example uses a different format string for each. Who said you can't do the same for C?
starball
CC BY-SA 4.0
2023-06-10T23:49:31.993Z
@starball, in C, `printf(fmt[language], color, object)` assumes that `color` will appear before `object` in the format string. But in French, the adjective appears *after* the noun.
Ray Butterworth
CC BY-SA 4.0
2023-06-10T23:54:19.723Z
@Bbrk24, I'm not aware that C allows specifying argument positions.
Ray Butterworth
CC BY-SA 4.0
2023-06-11T05:35:59.470Z
@RayButterworth so what? In your Python example, you're specifying payloads inline in the format string, and the order (naturally) is different between the two. How is it fair to say that having to specify a different order for C is a downside?
starball
CC BY-SA 4.0
2023-06-11T13:05:49.410Z
@starball, because when used, Python would say `print(gimme[language], colour, object)`, but C wouldn't know whether to say `printf(…, colour, object)` or `printf(…, object, colour)`, and that's not even considering how to generate the definite article.
Ray Butterworth
CC BY-SA 4.0
2023-06-11T20:34:22.300Z
@RayButterworth well, all I have to say about that is that that comes with runtime overhead, and you could build facilities to achieve the same in C, which just brings me back to what I wrote in my last paragraph.
starball
# What are the different syntax options for formatted string literals?
Posted by: username_0 on 2023-05-20
One option in Python is the f-string:
f"{a} {b} {c}"

Which is equivalent to:
str(a) + " " + str(b) + " " + str(c)

What are some other options for formatted string literals, and what are their advantages and disadvantages?
**Tags:** syntax strings string-interpolation
---
## 9 answers
### Answer by username_13 on 2023-05-21. Score: 15 | Accepted answer
Warning: without any ill-intent, this answer post responds to the question by asking more questions (hopefully useful ones, and hopefully while imparting some useful information or insight).

To start with, it's hard to say whether a particular choice or example will be an advantage or a disadvantage just by looking at a string formatting mechanism in isolation. It will really depend on a mixture of what the goals of your language are (Ex. with respect to mechanics or syntax), and following up on that, how the language works as a whole (Ex. with respect to how it is read and run by a machine), and in some cases, decisions you make that ultimately boil down to arbitrary or personal choices (Ex. with respect to syntax).

For example,

* Is it a goal of your language to have familiar syntax to people who program in existing, well-established languages targeting the same or similar problem/application-domains?
* Is it a goal of your language to help people who write and solve problems using non-programming languages (Ex. Mathematical notation)?
* Is it a goal of your language to provide some definition of "sane basic defaults" / batteries included, or instead to back off and let your users build their own abstractions and tools using the language? (In a sense- variations of opinionation)
* Is it a goal of your language to be syntactically rich, or syntactically simple? Both those higher-level directions have valid advantages and disadvantages themselves.

Do you see how it can be really hard for me to point at a syntactic choice a language made, separate it from the context of the language's goals, and then say "this is better in general because "? It would really only make sense for me to say "this made sense to the developers of this language because they wanted their language to achieve its goals, which included ".

---

Broadly speaking (unless the designers of the language didn't care, or weren't given the time to care deeply or design carefully), those kinds of higher design goals are what inform the more concrete choices that are more easily observable at a surface glance.

For example,

* How "deeply" is the mechanism ingrained into the language? (whether it has dedicated syntax / syntactic sugar, or doesn't have any particular special syntax and is really just something implemented *using* the language and lives at the library level of things. Or a mixture).
* How much room does the mechanism provide for users of it to customize it based on their user-defined data structures?
* What impact does the implementation have on costs in terms of space and time? If you lean to either end of the spectrum of library vs specialized-syntax, what limitations might you encounter due to the way your runtime and object formats (Ex. machine code, bytecode, interpreted script) work?
* Are there degrees of self-consistencies in syntactic choices with other related features in the language?
* What tradeoff is made between brevity and intuitiveness of mechanics (related to readability)?

---

The goal of this "big-list" answer post is not really to go very in-depth with how each of these languages work (because that's quite broad, hard for to do with my limited knowledge, and you might get bored), but to try to give you an idea that while there are broad categories we can box things into, the world is a bit wider and more colourful than it might seem from a surface glance, and to give you some ideas of what else there is to think about underneath the level of just syntax. Syntax is just an interface for all of what your language really is when you look beneath that surface, and I assume that's the meat we really care to get at.

---

I'll group what I know based on a more superficial(?) level of how the literals and values to format are arranged positionally at the source level, and order entries of the group very roughly based on what I know about how they fall on the compiled vs. interpreted spectrum (I'm human and I make mistakes. Corrections are welcome).

* There's a style where the "string literal" contains placeholders / slots that describe how to format what fills the placeholder / slot, and then the values that fill the slots are written separately. If I understand correctly, these mostly fall towards the "library-level" end of the spectrum. Ex.

  + [C style `printf`](https://en.cppreference.com/w/c/io/fprintf)
  + [C++23's `std::format`](https://en.cppreference.com/w/cpp/utility/format/format) (see also [the `fmt` library](https://fmt.dev/latest/api.html))
  + [Go's `fmt` package](https://pkg.go.dev/fmt)
  + [Java's `Formatter`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Formatter.html)
  + [.NET's composite format strings](https://learn.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting)
  + [Python's `str.format`](https://docs.python.org/3/library/stdtypes.html#str.format)
* There's a style where the values to format are / can be positionally arranged at the source level inside the "string literal". If I understand correctly, these mostly fall toward the "syntax-level" / "language foundational mechanisms" end of the spectrum. Ex.

  + [Julia's string interpolation](https://docs.julialang.org/en/v1/manual/strings/#string-interpolation)
  + [Java's string templates (JEP 430)](https://openjdk.org/jeps/430)
  + [C#'s interpolated format strings](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated)
  + [Kotlin's string "concatenation" / interpolation](https://kotlinlang.org/docs/java-to-kotlin-idioms-strings.html#concatenate-strings)
  + [Python's formatted string literals](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals)
  + [Dart's string interpolation](https://api.dart.dev/stable/3.0.1/dart-core/String-class.html)
  + [JavaScript's template literals](https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-template-literals)
  + [Bash parameter expansion](https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html) and [command substitution](https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html)

    And similar in other shells. Ex.

    - [Fish's variable substitution](https://fishshell.com/docs/current/language.html#expand-variable)
  + [CMake variable references](https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#variable-references)
  + There's more to see if you just look at [Wikipedia's String Interpolation page](https://en.wikipedia.org/wiki/String_interpolation).
* And then there are the approaches that don't use "string literals" at all but still are still designed for formatted text:

  + C++'s streams: [`operator<<`](https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2),
  + (technically speaking,) Java's [`StringBuilder`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuilder.html) + [`Object::toString`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html#toString())

---

From my (potentially faulty or misguided) observation, looking at a lot of the forms of syntax-level approaches that are commonly used, I see that there's nothing really about the part of the syntax related to the interpolation itself in those forms that really limits the user from putting arbitrary expressions there except for the limitations of what expressions can be written in any other expression-fitting part of the language's grammar. Which brings me back to my point on looking deeper and more holistically than just a single syntactic choice for a single mechanism in isolation.

---

Here's something that might go unforgotten, but shouldn't: How capable is your language of evolving with respect to particular syntactic choices here? *Does your language care about evolving?* Because if it does, since we can't see into the future and what programming paradigms may come, and it may be difficult to see what pain points might be found from experience with writing in the language at larger scales, it would be wise to think about this. This is part of why people who design messaging protocols leave reserved bits, or allow their messaging formats for arbitrary extension. Have you allowed for that kind of room for evolution? Or have you boxed yourself out of that? Or boxed yourself out of forms of evolution that could be more ideal for your goals?

And don't just think about your *language*. Think about the *code* that *users* of your language will write. How could your design choices make it easier or harder for them to evolve *their code* if your *language* evolves?

These questions really matter. Look back at the list above. Do you notice that some languages have multiple approaches? And in a number of those cases, those options did not all come into being at the same time? Some languages even might *want* to take multiple approaches, but doing so would cause old code to take on different meaning (dialect bifurcation (think Python 2 and Python 3)).

---

Lastly, unsolicited, I invite you to take a step back and also ask yourself another question.

Look at your language in a more holistic sense. Aside from any dedicated syntax, dedicated syntactic sugar, or dedicated library things you've decided to provide, in what ways / to what degree does the rest of your language enable its users to devise their own mechanisms for doing what *can't be done* with what your language gifts them in a neat box wrapped up and tied with a string (pun not intended)? Try using your language to do what it doesn't provide out of the box. Does what you write hold up to the goals of your language? (Ex. (potentially) readability and maintainability)
> **Comments:**
> **username_13** (2023-05-21): note to self: TODO: add some rust (the language) info. I forgot, and right now, I need to take a rest.  
> **username_13** (2023-05-21): meta note: in an effort to generalize my thoughts here, since there are so many questions like the one here, I've factored some of the "core"out and put it [here](https://languagedesign.stackexchange.com/a/889/251)  
> **username_14** (2023-06-10): Another factor is i18n, where word order in messages can be different. In C, having a format string for each language doesn't work. In python one can say: `gimme['en'] = f"Give me the {colour} {object}."`
`gimme['fr'] = f"Donnez moi {definite_article(object)} {object} {colour}."`. Yes, it would be more complicated than that, but it makes the process easier.  
> **username_2** (2023-06-10): Can’t you say `%2$s %1$s` to reverse the order in C? I know at least Java supports something like that.  
> **username_13** (2023-06-10): @RayButterworth how does it not work? I fail to see. Your Python example uses a different format string for each. Who said you can't do the same for C?  
> **username_14** (2023-06-10): @starball, in C, `printf(fmt[language], color, object)` assumes that `color` will appear before `object` in the format string. But in French, the adjective appears *after* the noun.  
> **username_14** (2023-06-10): @Bbrk24, I'm not aware that C allows specifying argument positions.  
> **username_13** (2023-06-11): @RayButterworth so what? In your Python example, you're specifying payloads inline in the format string, and the order (naturally) is different between the two. How is it fair to say that having to specify a different order for C is a downside?  
> **username_14** (2023-06-11): @starball, because when used, Python would say `print(gimme[language], colour, object)`, but C wouldn't know whether to say `printf(…, colour, object)` or `printf(…, object, colour)`, and that's not even considering how to generate the definite article.  
> **username_13** (2023-06-11): @RayButterworth well, all I have to say about that is that that comes with runtime overhead, and you could build facilities to achieve the same in C, which just brings me back to what I wrote in my last paragraph.  
---
### Answer by username_1 on 2023-05-20. Score: 6
Swift Style
"\(a) \(b) \(c)"

"""

    \(hello_world_str)

"""

This syntax is reasonably lightweight and doesn't conflict with the common unformatted string syntax (many languages that use backslash as a string escape symbol will not allow unrecognized escape sequences like \(, and such occurrences regardless are far less common than the literal string characters { and }).
> **Comments:**
> **username_2** (2023-05-20): Worth noting that it's possible to add custom overloads of this: https://languagedesign.stackexchange.com/a/249/15  
---
### Answer by username_3 on 2023-07-12. Score: 4
I would like to talk about the old FORTRAN formats at least from historical respect:
      WRITE (6,7000) month
      WRITE (6,7000) day

7000  FORMAT(15H Hello, world:  , I3)
      END

Why largely obsolete now, they include some interesting features:

The formatting string (number formats and surrounding text) is defined separately from the statement that prints the values. It can be far apart (it was common to have them at the end of the program). This reduces the "visual noise".
The formatting string is referenced by the label, 7000 in this example (6 is the output channel, the terminal) and can be shared by multiple print (write) statements. If the same or related values are printed, the format only needs to be defined once.
All printable characters can be used in the message without any escaping, providing the length of the text (15 characters) instead. While it is very error prone to count and adjust these counters, reading is easy.
I3 is the number format (integer, field width of 3). You can read here about the possible format specifiers.
> **Comments:**
> **username_4** (2023-11-05): An advantage of this approach is that it facilitates the use of code generation tools to generate bespoke code which handles formatting.  When using something like `printf`, there's often no way for an implementation to include only the features that a program actually uses, but the needs of bespoke formatting functions could be determine statically.  
---
### Answer by username_11 on 2023-05-20. Score: 3
Kotlin Style
Kotlin has pretty similar string interpolation to Python. The difference is that you don't need to specify a special f-string with an 'f' before the string but do need to specify the interpolation with a '$'.
As an example from the Kotlin docs:
val name = "Joe"
println("Hello, $name")
println("Your name is ${name.length} characters long")

This looks neater as you don't need the {} braces around every expression, but you can include them for longer expressions. You also don't need to specify that it is an f-string before using the interpolation.
> **Comments:**
> **username_12** (2023-07-12): This, or something like it, is also used in Perl IIRC.  
---
### Answer by username_5 on 2023-07-13. Score: 2
## No built-in syntax

If your language either supports procedural macros or allows dynamically accessing variables by name, you can avoid having special syntax for formatted strings at all and instead implement them as a macro/function in the standard library or even an installable package.

An example of the macro approach: Nim's [`std/strformat`](https://nim-lang.org/docs/strformat.html)

An example of the reflection approach: Arturo's [`render`](https://arturo-lang.io/documentation/library/strings/render/)
---
### Answer by username_6 on 2023-07-12. Score: 2
A lot of examples of format string literals have already been given. I'll just mention two issues here:
Internationalization (i18n)
As mentioned by Ray Butterworth:

In python one can say:
gimme['en'] = f"Give me the {colour} {object}."
gimme['fr'] = f"Donnez moi {definite_article(object)} {object} {colour}."


The problem here is that this only works when declaring all the translations in the code. You can't load f-strings from a file, unless you use eval(), which then opens you up to lots of security issues.
Separating code from translations is very important if you want to outsource translating your code to a team of people that are not coders. For example, with GNU gettext, a file can be created by a tool containing all the original format strings in your code, and then translaters can make a translation file for all those strings for their language. That file containing translations can be loaded at runtime, no recompilation necessary.
Another issue with the Python example from Ray is that it's very slow if you have translations for lots of languages: each format string literal is evaluated as it is added to the dict gimme, even if you are only ever going to use one of them. And you cannot move the format string literals out of the function you are using them if it references local variables.
Equivalence
You mention:

f"{a} {b} {c}"

Which is equivalent to:
str(a) + " " + str(b) + " " + str(c)


Being able to specify how a format string literal is interpreted and what it is equivalent to is great. You can then think of doing that in other languages as well, not just interpreted ones! Wouldn't it be interesting if this could be applied to C++? What if:
std::cout << f"Hello {name}, the answer is {6 * 7}!\n";

Was defined to be equivalent to:
std::cout << std::format("Hello {}, the answer is {}!\n", name, 6 * 7);

It's a relatively easy change to the language, and makes use of existing library features to do the heavy lifting. Even better would be to allow the formatting function to be used to be replaced by a custom version (just like new can be replaced by a user-defined function in C++). This would open up new possibilities, for example automatically applying gettext() on the format string to internationalize your program with very little changes.
> **Comments:**
> **username_6** (2023-07-13): Hm, `operator f""(const char* str, std::size_t size, auto&&... args)`? Or if C++ had reflection like in @xigoi's answer, maybe you'd only need C++11's user defined literals.  
---
### Answer by username_7 on 2023-07-13. Score: 1
# RegEx style (similar to shell)

### I’ll just use PCRE2 regex for this example.

  

Match expression (to get input since formatting values are stored in capture groups): `(.*)\n(\d*)`

Substitution expression (format string): `My name is $1 and I am $2 years old.`

[Try it online!](https://regex101.com/library/bmex4E)
> **Comments:**
> **username_8** (2023-07-13): How does this answer the question?  
> **username_7** (2023-07-13): @mousetail It's a way of formatting  
> **username_8** (2023-07-13): This question is about syntax options for formatting  
---
### Answer by username_9 on 2023-05-20. Score: 1
Go offers excellent support for string formatting in the printf tradition. So, based on the formatter (%v, %t, %d,%s, etc.) it can handle different types of parameters and print the result as a string.
<https://gobyexample.com/string-formatting>
> **Comments:**
> **username_1** (2023-05-20): OP is specifically asking about formatted string literals (such as Python's f-strings), rather than string formatting in general (such as Python's `str.format`).  
> **username_9** (2023-05-21): f-strings is the better replacement of python's previous both %-formatting and str.format()  
---
### Answer by username_10 on 2023-06-10. Score: 1
Shell style
Like in shell:
"hello, $name"

name is a variable.
---
