Hacker News new | past | comments | ask | show | jobs | submit login
JEP draft: String Templates (Final) (openjdk.org)
64 points by ludovicianul 8 months ago | hide | past | favorite | 128 comments



I think having multiple processors is very smart exactly due to the outlined reason - making sure the interpolated result is safe for the system that will consume that string, be it a query language or json or something else.

f"" vs STR."" is really a quite minimal difference, and I think worth it. Having the "." operator here mean "interpolate RHS using LHS" seems a nice balance between terseness and explicitness.

As for "\{" being a divergent choice, frankly who cares.


These are some good examples:

    var $ = STR;
    var $h = new HtmlTemplateThing();
    var $j = new JSONTemplateThing();

    var name = "John";

    var s = $."Hello \{name}";
    // HTML escaped
    var h = $h."<b>\{name}</b>";
    // JSON escaped
    var j = $j."""
        { "name" : "\{name}" }
    """;  // JSON escaped
I love this one:

    var $db = new DBConnectionTemplateThing();

    // SQL Escaped and processed
    PreparedStatement st = $db."select * from table where name = '\{name}'";
    
Or:

    var $x = new XMLTemplateThing();

    // XML escaped and parsed
    Document d = $x."<xml>\{name}</xml>";
This is pretty powerful. They selected \{ for the start of expressions because of the legacy of Java Expression Language (EL) which came from JSP and JSF.

Doesn't look that terrible to me.


“\{“ reminds me of Swift’s “\(“. So I wouldn’t think it’s even that divergent. And Java devs are already used to backslashes peppering strings (me included).

https://developer.apple.com/documentation/swift/stringinterp...


It's weird they didn't mention JavaScript's Tagged Templates because that's exactly what they propose. Am I missing something?

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


Yes, it’s nice to see features flowing from JavaScript -> Java like tagged template literals, now JavaScript is caught up on things like “class”.


I think String Templates are pretty cool. For example it enables "tagged template literal"-like behavior which is super powerful in JS land.

I used it to support a LiveView implementation for Java: https://github.com/floodfx/undead

Sure the syntax isn't "pretty" but understandable and you get used to it like anything else.


The whole reason for string interpolation is to have a “pretty” syntax.


But the security problems that string interpolation introduces are one of the reasons why Java has decided to reject string interpolation as a language feature in favour of string templates (you can use string templates for interpolation as a special case of a template processor, but that's not the feature's raison d'être). The reason for string templates is to improve the convenience and (very poor) security of string manipulation.

The JEP explains why Java is getting string templates and is not getting string interpolation (as a language feature).


> Thus if we forget to use a template processor such as STR, RAW, or FMT then a compile-time error is reported:

    String name = "Joan";
    String info = "My name is \{name}";
    | error: processor missing from template expression
Were literals like "\{" always causing an error?


Yes, because it's the escape character.

It's the reason they didn't chose "${" like many other languages. Because that's a valid sequence in a string literal.


Which is a nonsensical reasoning they're also requiring a template processor, so string templates were previously impossible in two different ways.

`\{` as an interpolation leader would make sense if untagged string literals became implicit STR templates, but that's not the case.


I guess they want to force you to choose interpolator. So that you won't implicitly use STR when you should have explicitly use SQL.


> I guess they want to force you to choose interpolator.

In which case using `\{}` as the interpolation signal is completely unnecessary, because the new syntax already solves the backward compatibility concerns.

Using just `{x}` like C# and Python, or `$x`/`${x}` like Kotlin, would have sufficed and made the syntax a lot more palatable.

So would using postfix format specifiers, because that printf-style prefix garbage is just gnarly.


\{ protects you from forgetting to use interpolator at all. No other syntax that uses same delimiters as string literal would.


Yes, the escape sequence `\{` is not valid and javac would report an "illegal escape character" error.


Yes. '\' denotes an escape sequence, and "\{" was/is not a valid escape sequence.


I wasn't able to tell from this document, IMO since they are focused on safety as a reason for their templates approach, they should include some defaults for common scenarios if they'd liked this to gain wider usage. For example that QueryBuilder they used for SQL would be useful.

Too often I see experienced developers using string interpolation for SQL and not realising it's open to injection. I feel the document's intentions are good but because the implementation looks so verbose they should make it as frictionless as possible to gain wider adoption. Else all that's going to happen is people will only ever use STR.


The nice thing about this design is that the correct thing is also easier than the incorrect thing:

    var q = DB."SELECT foo FROM bar WHERE a = \{b}";   // PreparedStatement?
    var results = conn.execute(q);                     // ResultSet
is shorter and easier to write than the non-safe alternative.

That said, I wonder how often people are writing queries out by hand like that these days vs using ORMs or jOOQ.


I think the whole thing is pretty useless, but I guess the point is that with your own template format you could write a string template format that fully escapes sql variables, for instance.

Yes, we already have that problem solved with JPQL or even just plain prepared statement but that’s never stopped anyone…

And yes, you could also write a message formatter the current Java that does that…


I’d go further and say they shouldn’t provide STR. The difference in syntactic (in)convenience between

    "..." + foo + "..." + bar + "..."
and

    STR."...\{foo}...\{bar}..."
is negligible. And then the syntax

    FOO."..."
would at least imply that some special processing is going on.


Except then it would still be absolutely trivial for people to write their own string-interpolating template processors, which they would definitely do, and so we figured we might as well offer a standard one (that also offers better performance than hand-rolled ones). It is difficult to find the right balance between educating people to do "the right thing" as we see it and rolling with the recognition that they not always will. I wish we could say there's some formula we apply, but we need to exercise such judgment with lots of features and it's never a trivial decision. In this case we figured that if we make the thing people will want to do anyway no easier than the "right thing", that's probably as good as we can do, all things considered.


Unpleasantly verbose, especially compared to Kotlin. They'd have come up with a much better approach if they had to add it to their list of current implementations.

    C#           $"{x} plus {y} equals {x + y}"
    Visual Basic $"{x} plus {y} equals {x + y}"
    Python       f"{x} plus {y} equals {x + y}"
    Scala        s"$x plus $y equals ${x + y}"
    Groovy       "$x plus $y equals ${x + y}"
    Kotlin       "$x plus $y equals ${x + y}"
    JavaScript   `${x} plus ${y} equals ${x + y}`
    Ruby         "#{x} plus #{y} equals #{x + y}"
    Swift        "\(x) plus \(y) equals \(x + y)"
    Java         STR."\{x} plus \{y} equals \{x + y}"


There's literally two sections explaining why it is the way it is.

> String interpolation is dangerous > Can we do better?


But they've made the common case much worse.

For the 'injection' case, they could define an annotation which stops interpolation on a provided parameter, and provide a more verbose method to handle templated interpolation correctly.

A sample syntax by JetBrains is below. [0] In future, this could be leveraged to block/warn against dangerous interpolations

    @Language("SQL") // This adds SQL highlighting, encouraging developers to use it
    String query = "SELECT * FROM Person p WHERE p.last_name = '${name}'" // future warning/error
    
[0] https://www.jetbrains.com/help/idea/using-language-injection...


Yeah that's great for new code. What about all the old code people have written and they want to upgrade to the new version of the language? `\{` used to be invalid syntax for the string, so if they add meaning to that syntax then it won't break old code. There's a lot of extant code for Java.


"IDENTIFIER, PERIOD, LITERAL" is also invalid syntax before this JEP, and it's the only way to enable string templates. The processing of untagged string literals is not changed.


It's not better though. The STR template processor behaves the exact same way as all the other examples, and it's the one that all the inexperienced devs prone to this kind of injection attack will use.


The approach of defining template processors is definitely better. Moving from unsafe to safe is "just" switching STR to whatever secure processor team writes.


They won't use it if the APIs for generating HTML/JSON/SQL don't take String (or deprecate the old methods that do). The various APIs can support only their own, safe processors, and if an API doesn't take a String then you can't pass it interpolated strings.


Note, that Java had to maintain backward compatibility, so they couldn't inject any new syntax into existing string literals. So, they had a choice between:

1. Introducing syntax for new kind of string literals (like JS did)

2. Make some kind of explicit function/constructor call (like they ended up doing).

Advantage of 2 is that it doesn't require any new support from IDEs/parsers/code quality tools/etc. It is slightly more verbose, but not as verbose as some other Java syntax. IMO they've made the right decision.


But the solution does need support from IDEs and parsers. STR."\{STR."\{a}"}" is a valid expression, now, that uses a variable, and looks nothing like any previously valid expression. Given that it is an entirely new kind of expression, it's also unclear why they would choose \{ over { or need the dot. Is there some reason that they couldn't have chosen STR"{a}"?


Except they did both: `\{` is not currently valid, so the "explicit function / constructor call" is completely unnecessary.

Furthermore, they went on to use a printf-style formatting spec prefixing the template leader.

> Advantage of 2 is that it doesn't require any new support from IDEs/parsers/code quality tools/etc.

Of course it does, the sequence "IDENTIFIER, PERIOD, STRING LITERAL" is currently invalid, anything beyond a tokeniser should choke on it.


Can I call out JavaScript for using backticks for a clean distinction between templated and untemplated strings:

- no strange leading character(s) (per C#, VB, Python, Scala, and now Java)

- templated strings are actually distinguished, so don't have to worry about accidentally running into template literals in normal strings (unlike Groovy, Kotlin, Ruby)

- the distinguishing mark appears at the end as well as the beginning, for slightly better legibility.

- Swift is quite nice in that the backslash is already an escape character for normal strings, so no issue with accidental use, but {} would have been a better choice than () as the former are rarer in normal strings.


> no strange leading character(s) (per C#, VB, Python, Scala, and now Java)

There are no strange leading characters in Java, either. A template expression is a special case of an instance method call (it's a call to the `process` method on the template processor), and the "leading characters" are the same ones Java already requires for all instance calls. There's nothing strange about them; what is new (and therefore possibly strange) is the use of `"` for the method call instead of a method name followed by `(`. In other words, the new syntax Java added is what follows the dot in the method call to `process`; everything up to and including the dot is normal Java syntax. This is important to emphasise that a template string expression is an a method call that may (although normally shouldn't) even have a side effect.

> templated strings are actually distinguished, so don't have to worry about accidentally running into template literals in normal strings

Same here. `\{` inside a string remains a syntax error, as it always has been. Also, Java is typed (and the template expression requires a receiver of type StringTemplate.Processor) and there cannot be any ambiguity, and so it's unnecessary to introduce yet another punctuation mark. JS needed further distinguishing syntax because it is untyped.


I understand what you are saying, but on the face of it we have:

"my normal string"

`my templated string`

vs

"my normal string"

STR."my templated string"

probably we can agree which looks cleaner (though I grant, maybe not as 'pluggable')


You're talking about string interpolation, and while string interpolation is a special case (and a side effect) of the string templates feature, it's not the goal of the feature. In fact, the feature is designed to help you avoid string interpolation in favour of safer template processors. Ideally, where it matters most, you wouldn't use STR."..." at all, but rather HTML."..." or SQL."....".

So the question that's relevant to the core of this feature is, which looks cleaner:

    SQL."..."
or

    SQL`...`
Because this is an actual method call, because Java's type safety and the fact that `\{` is a syntax error in a string means that string and template literals cannot possibly be confused, I think that the former is nicer and clearer for Java programmers and it's only longer by a single character; in fact, I would say that the latter would look very foreign (you could ask whether SQL"..." would be better, but this is an instance method call, and dropping the standard dot, I would argue, would not make things better).

You can see it better if you look at the JS examples here (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...), such as:

    console.log.bind(1, 2)`Hello`;
Which, in Java syntax, would be written as:

    console.log.bind(1, 2)."Hello";
I think it's much less weird for a Java programmer.

Also, it's not about "plugging in" other processors. The processor is chosen by the library. If a library offers an HTML processor as part of its API but not a method that takes a string, you simply cannot use STR even if you wanted to. The processor is more a constraint imposed by the API than a plugin you choose to use or not (as the type of the template expression is determined by the processor, and for the interesting processors it is not a string at all but rather a PreparedStatement or some JSON class or HTMLNode).

JS offers string interpolation in addition to string templates (or "tagged template strings", as they're called in JS), but we don't offer string interpolation as a Java language feature at all, because it's really dangerous and should be discouraged (certainly not made easier to use than safer templates). But supposed we did want to offer string interpolation in Java, then its syntax would simply be "...". There would be no confusion between a string and a string template even then.


But the whole point of the JEP is to offer a different and better feature than string interpolation because the JEP claims that string interpolation should be avoided. Saying that using it for string interpolation is more verbose than the very thing the JEP tried to avoid doing is missing the whole point. The idea is that in the most important cases you should avoid the `STR` processor in favour of a JSON, HTML, or SQL processor.

You can agree or disagree with the JEP's goal, but pointing out that the JEP manages to discourage the very thing that it sets out to discourage merely acknowledges that the goal is met.


> The idea is that in the most important cases you will not use the `STR` processor but rather a JSON, HTML, or SQL processor.

That idea is evidently idiotic as demonstrated by javascript which has this exact feature, in a better form (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...): the most common template literals by far are untagged.


Right 'cause JS is so well-trusted with large, important server side software that it must be "evidently idiotic" not to follow exactly in its footsteps. Unfortunately, Brian Goetz and Guy Steele spat this one out off the cuff after only two years of study and experimentation with alternatives and failed to see that it's evidently idiotic; neither did most people who've used the feature.


Even if I think that Guy Steele is a genius, an argument of authority is always a bad argument. Better listening to the foot soldiers than staying in your high tower.

Using '\' instead of '$' does not allow $variable as a shortcut to ${variable} making the syntax objectively harder to read.

Using '\' cleverly helps to detect when the processor is missing at compile time but it does not matter because the syntax mandates a big STR in front.


> an argument of authority is always a bad argument

True, but so was the argument I responded to (JS did it differently) and this is, after all, the internet. But there was also another point I was trying to make, which is that some people seem to have it as their null hypothesis that Java's designers get things wrong or don't do what the people want even though they are not only among the most experienced language designers around but also among the most consistently successful, and usually by a pretty wide margin. I think that means that at the very least they deserve the benefit of the doubt and perhaps another moment of contemplation.

> Better listening to the foot soldiers than staying in your high tower.

Which is why the designers didn't just trust their guts and experience, but designed the feature in an iterative process with actual "foot soldiers" trying it out (as most new Java features are designed, and as the Preview process was created to support). The criticism, on the other hand, seems to mostly come from people who have not actually tried it out, and it is they who are staying in their high tower.

When designing new Java features and asking for feedback we always emphasise that speculating is something anyone can do, and what we need is people trying out the prototype or preview and reporting on their actual experience. Such feedback is always valuable and taken seriously. On the other hand, speculation offered by people who have both given the matter less thought and who have had less experience with the feature than its designers is usually not very useful.

It is really very easy for a Java programmer to have an actual impact on the design of new features: Step 1 — try the feature for a while in EA or in Preview; step 2 — report on your experiences to the mailing list. If someone can't even spend the time to do that, how can we know that they've spent more than 30 minutes thinking about the problem before sharing their speculation that we must have done something wrong?

Now, it is true that while we know that string interpolation is problematic, we can only speculate that offering it only as a special case of string templates would improve matters. But we figured that if, despite our analysis, we end up being proved wrong, it would be an easy matter to also offer string interpolation as a language feature (e.g. by making it the default processor).

> Using '\' instead of '$' does not allow $variable as a shortcut to ${variable} making the syntax objectively harder to read.

Python (f-strings), JS, C#, and Ruby -- the most popular language that have had either string interpolation and/or string templates before Java -- also don't allow for such a shortcut (I believe the only top language that does support this shortcut is PHP), and if quite a few language designers didn't think that the shortcut was a significant advantage I don't know how "objective" you can claim it to be.

$ also creates some other difficulties, as it is quite common in Java templating libraries (even in JS, the syntax used by templating libraries differs from that used by the language, otherwise it causes bigger annoyances). It would mean that $ would need to be escaped in some contexts and not in others, making adoption of the feature less smooth than we'd want (see https://mail.openjdk.org/pipermail/amber-spec-experts/2023-A...).

> Using '\' cleverly helps to detect when the processor is missing at compile time but it does not matter because the syntax mandates a big STR in front.

Like all instance calls in Java, this instance call also mandates a receiver; it's not some special prefix. If you don't like the "big" STR you can assign that particular template processor object a different name, including one named `$` if you like, because that's a valid Java identifier. I.e. you can do:

    var $ = STR;
    $."Hello \{x}!"


We had high hope that unlike SUN, Oracle will listen.

> Iterative process

please send a link to a video of a designer from Oracle presenting the string templates at a conference. This is not Loom, there is no iterative process.

> Python, JS, and C# also don't allow for such a shortcut

The syntax of C# or Python is also lightweight, fine by me.

> it's not some special prefix

I get that, but not using a constant like STR is an anti-pattern, as you said it's a virtual method call.

> The criticism, on the other hand, seems to mostly come from people who have not actually tried it out

Ask designers to go to conferences and you will get real feedback.


> We had high hope that unlike SUN, Oracle will listen.

Sorry to disappoint (or not) but much of the technical leadership are the same people...

> please send a link to a video of a designer from Oracle presenting the string templates at a conference.

How about not one video but two, not of any designer but of the chief language designer talking about the feature not at any conference but at what is probably the biggest Java conference?

https://youtu.be/TIHx6MNt79Y?si=Qwj0ER-yxlS-Flxq&t=1972

https://youtu.be/DlTUMjg7DD0?si=6urFyuyF_jCtZ0H-&t=1099

> This is not Loom, there is no iterative process

a. you're wrong — the discussion and iteration have taken place on the amber-dev and the amber-spec-experts mailing lists — and b. I've received my share of accusations of "not listening" (and sometimes even worse) on Loom. It may not have been from you, though. :)

As always, feedback that follows actual usage is taken very seriously and has a significant impact.

You're right, however, that it's a much smaller feature than virtual threads, and so the public part of the design process didn't last for over four years but only for a little over two years (https://mail.openjdk.org/pipermail/amber-dev/2021-September/..., https://github.com/openjdk/amber-docs/blob/master/site/desig...).

> The syntax of C# or Python is also lightweight, fine by me.

Python has string interpolation but doesn't have string templates; Java has string templates but doesn't have string interpolation as a language feature. You're comparing syntax for two different features. As for C#, Java-like string templates can be mimicked [1], but the syntax isn't really lighter-weight. Instead of `SQL."SELECT * FROM SomeTable WHERE Age = \{age} AND Name = \{name}"` you'd write `SQL($"SELECT * FROM SomeTable WHERE Age = {age} AND Name = {name}")`; note that the method call to SQL is necessary to get a similar feature to Java's.

> I get that, but not using a constant like STR is an anti-pattern, as you said it's a virtual method call.

It's just a final field. You can do `final StringTemplate.Processor<String, RuntimeException> $ = STR;` and it's just as much of a "constant" as STR is. Of course, whether or not you should make string interpolation easier is up to you; after all, the reason we didn't add string interpolation to the language is because we think that making it easier is a bad idea given the vulnerabilities it has caused.

> Ask designers to go to conferences and you will get real feedback.

But they do. But just to clarify, feedback about a feature is from people who've actually used it; otherwise it's just a speculative opinion.

[1]: https://bengribaudo.com/blog/2021/04/13/5596/intercepting-st...


Both the syntax and the semantics are awful. They are overthinking it.

Processor should not require to allocate a list of objects do to string templating. Only STR and FMT get good perf because they are specialized by the compiler.


> Only STR and FMT get good perf because they are specialized by the compiler.

Sort of. The specialisation happens for any user of MethodHandle.invokeExact, which is what those processors use (i.e. the compiler doesn't specifically know about STR and FMT), it's just that the MethodHandle API for template processors is not yet public. I expect it will be made public later on.


Does not allocate a list of objects in C# :) (there is an intermediate pooled buffer, which is then collected to a newly allocated string of an exact size)


About time java introduced escape analysis /s


Sadly escape analysis in Java is weak. In this case, it only works if all the template values do not escape.


What's Kotlin going to do about that? Will they adopt their syntax or make it use the same API internally?

This seems just like another feature of the JVM mother language that diverges from the implementation of other often-used JVM languages like Kotlin (thinking of nullability, type reification and structured concurrency and record types). It will be interesting to see what happens when Kotlin is continued to be pushed as the language for Android etc. while Java is being used by the majority of JVM devs.


Inability to reasonably operate an API that has that StringTemplate type somewhere in a method signature would be a dramatic change of direction for kotlin. I'd be surprised if they didn't already have something in the pipeline to support \{it} strings on the syntax level, it's not like they pretend java-side progress didn't exist.

The existing ${it} syntax is tied to string on the output, so it can't be repurposed. The java approach on the other hand keeps the output generic, so that it would also keep the door open for similar not-string compatibilities in off-JVM kotlin implementations. Whereas the ${it} the syntax kotlin already has couldn't do that. An approach like changing its semantics to define something that isn't a string when it exists at a StringTemplate.Processor call site would be terrible I think, php-grade terrible. At least as long as they don't also introduce that formatter-dot-template syntax which I'd consider a pointless redundancy with what kotlin already has: formatter{template} is already possible, expect for a way to write a template literal that resolves to something other than string.

What I certainly wouldn't expect is anything reminiscent of "automatically imported into every Java source file".


> often used

It's certainly a very visible language and one often talked about, but if you look at Google trends for Java versus kotlin you're looking at about 10% of the adoption that Java has or less.


The languages don't have much surface area of features to search about. Far more google queries will be about API than about syntax. I wouldn't be surprised if the browser histories of kotlin developers, on average, contained far more occurrences of "google.+java" than of "google.+kotlin".


It's a whole new string: " unescaped; multiline

In 1996, I thought java would be the new COBOL, and could endure for 20 years - now almost 30. This prioritization of "whole product" concerns, like security (bobby tables) and error-proneness, ensures longevity.

Also capture developers and codebases with its intricate magical features.


Multiline strings were added back in Java 15.


Ah, unescaped quotes too. So not "new"... but within single quotes, looking like an ordinary string literal: strange. What they're doing is confusing, and evil!


Would it hurt them to use ${x} instead of \{x}?

I mean, "${x}" could already be a literal in strings before, but they have the <processor>. prefix to the string, which no old code would have. One needs to actively use it, and so that someone can also actively check not to write an unescaped ${x} when they don't want interpolation (like in other languages that use it).

Also the whole processor for escaping is imho ill-conceived. Escaping for a specific language like SQL should happen on the formatter instructions level, e.g.

  "SELECT airport_code FROM airports WHERE name != '%sql.string\{surname}'"
  ->
  SELECT name FROM table_foo WHERE surname != 'O''Hare'
or something to that effect (and similar for sql.identifier etc).

This way you could easily write classes with collections of methods to format a specific kind of language's values - and not have write a full formatter that parses and understands the whole string in context (as I assume is the case now, if you don't just use the naive STR/FMT one, as 99% will do).

Especially since you might need to handle multiple languages escaping rules in the same template, if you include strings for multiple languges/contexts in your template. What you do for that? Write the cartesian combo of template processors and make each understand and parse multi-language string tokens?


> Would it hurt them to use ${x} instead of \{x}?

There are multiple reasons to prefer \:

1. In Java, \ is already the character that signifies that what follows has a special meaning, while the use of $ is foreign (to the language).

2. `\{` is a syntax error inside string literals, which means it appears nowhere inside string literals, while $ is fairly common; it would also mean that $ will need to be written differently inside string and string template literals.

3. The use of $ for interpolation is common in Java templating libraries, and it's preferable for the language to use something different (in JS, where $ is used by the language, templating libraries also use something else, like `{{`). See https://mail.openjdk.org/pipermail/amber-spec-experts/2023-A...

> or something to that effect (and similar for sql.identifier etc).

You can already do that if you want:

   X."blah \{sqlString(x)} blah";
But this feature is being added to Java to solve the pretty serious problem of code injection, and so the more important thing is the selection of the processor, which ensures safety, i.e. an HTML API will offer an HTML processor and will not accept strings. Remember, string templates are most useful when what they produce is not a string, but rather construct a specific API entity.


>But this feature is being added to Java to solve the pretty serious problem of code injection

My take is that it will do little for code injection. Most programmers will use STR/FMT, and unless they offer an HTML or an SQL processor in the stdlib, they wont be used.

>Remember, string templates are most useful when what they produce is not a string, but rather construct a specific API entity

Sure, but the processor can do little short of implementing full parsing to understand the context of say HTML or SQL, right?


> Most programmers will use STR/FMT, and unless they offer an HTML or an SQL processor in the stdlib, they wont be used.

New processors obviously can't be used unless they're offered by a library, but when they are, they must be used. The libraries simply won't offer an API based on strings (and, therefore, interpolated strings), or if they already do, they will be able to deprecate them. If an HTML library has no API that takes strings, then STR/FMT simply can't be used. The library can enforce the safety of its API.

> Sure, but the processor can do little short of implementing full parsing to understand the context of say HTML or SQL, right?

Yes, that's the point. An HTML library will offer an HTML processor, and similarly for a JSON or SQL library. I'm not apprised of the exact status, but I believe that the team specifying JDBC is looking into offering a SQL processor as part of JDBC.


Edit: This comment was written when the original comment was just "Would it hurt them to use ${x} instead of \{x}?"

This is covered in the article under "Alternatives", in the section beginning with:

> For embedded expressions in string templates, we considered adopting the ${...} syntax from the Java EE Expression Language (EL) rather than \{...}. However, this would force developers to escape every $ sign in the literal text of a string template while continuing to write $ without escapes in string literals and text blocks. This inconsistency could all too easily lead to errors.

...

> With the syntax we have chosen, frameworks can ease migration by providing a template processor that understands EL syntax. Developers can continue using ${...} while also having access to the Java environment via \{...}:


>However, this would force developers to escape every $ sign in the literal text of a string template while continuing to write $ without escapes in string literals and text blocks.

The other side is that now they'll make them think they can also write \{foo} in string literals and text blocks, and they'll find out it doesn't work.


I would assume that will keep being a compilation error.

It also seems to be a very "think of the morons" point to raise.


Correct, this example is also in the JEP:

  String name = "Joan";
  String info = "My name is \{name}";
  | error: processor missing from template expression


How is it better?

Just different, and using dollar sign adds another shift press.


The language spec is the only place able to introduce meaning to a source byte sequence starting with a backslash that has been invalid before (e.g. not double-backslash, or backslash-u). ${ on the other hand never been an invalid byte sequence inside a string literal, and was hence already used by many APIs. It's nothing but courteous by the language people to avoid avoidable collisions. Keep in mind that this new syntax is completely open to everybody else who might have a use case for strings-with-expressions, it's not like they are appropriating a previously blank spot for exclusive use.


>How is it better?

Much more older and common use and association (even their own "Java EE Expression Language" uses it), and not confused with escaping a character (like \n, \t) etc.

Pricinple of least surprise, avoiding NIH, and stuff.


> Much more older and common use and association (even their own "Java EE Expression Language" uses it)

That was one of the main reasons not to use it; even in JS templating libraries use different syntax from that of the language's $ (see my other comment).

> and not confused with escaping a character (like \n, \t) etc

That would not be a confusion at all but the very point: \{ is just like \n or \t, i.e. gets a special interpretation rather than a literal one.

> Pricinple of least surprise

\ in Java is standard for that purpose (special interpretation in a literal); it is $ that is foreign.

> avoiding NIH

That is not so much of a principle, although it could be if the language was rejecting some otherwise universal choice, only that's not the case here at all. Of the other popular language with either a similar feature to Java's string templates or with string interpolation -- JS, Python, PHP, C#, and Ruby -- only JS and PHP use $ (and only PHP uses $ with the "shell" shortcut of $x). Or, if you only want to look at the "big three" -- JS, Python, and Java -- each has a different syntax from the other two, and only one uses $. Even if you look at all programming languages in the world, only a minority of programmers using a language with string templates and/or string interpolation use one where $ is used for the value syntax. Not only is it not a near universal choice, it's a minority choice.


The comments about this feature are always so tiresome. Please just scroll down and read the "Alternatives" section at the bottom. They're not idiots. They're working within backwards compatibility constraints. They can't just do it like other languages.


C# introduced `#nullable enable` to change the behaviour of reference types.

Java could do the same to change the behaviour of `$` inside a string (along with a project-level config to make this the default).

Let developers opt-in to better syntax, rather than using significantly worse syntax to support legacy code

https://learn.microsoft.com/en-us/dotnet/csharp/nullable-mig...


It's moot, anyway, as parser changes are already required by the STR." part. About the only possible defence is that one could use the same lexer, but even that's not true because you can presumably now embed a multi-line string in a single-line string, like so:

  STR."\{STR."""
  \{hey}
  """}"


Even with their constraints they could have made this nicer, especially around the default formatter. Always requiring an explicit formatter is a classic example of Java being unnecessarily verbose, `\{ ` already wasn't permitted by previous java compilers as it was an unknown escape sequence so we could have nicer templates for the stock formatting like "\{foo} bar".


All super weak arguments IMO. Problems that somehow every other language doesn’t have?


Other languages are not attempting to be backwards compatible with Java.


One of the arguments is that existing $ in strings would have to be escaped. Every other language supported $ in strings before interpolation appeared. Not Java specific.

Every other language is susceptible to SQL injection style attacks. Not Java specific.


Few other languages are as committed to backwards compatibility as Java though.


Super weak how? They're quite reasonable and weighed-out.


Those are extremely weak arguments.

Elixir has string interpolation and custom "templates" or whatever they are called without the ugly syntax:

  ~h"custom one"
  ~s"custom two"
etc.


~x”hi” is basically the same amount of ugly to me as X.”hi”


I find it significantly less jarring than STR."hi"


How are these interpolated?


I think most people read the whole thing. I have. It's still very ugly


You can not use the excuse of the backward compatibility twice.

If the string template is prefixed by a processor STR."foo" instead of "foo" then you do not need \{variable} instead of $variable.


You don't want friction on the default path to be too low because that would inevitably increase the occurrence of default path where it must not be used, e.g. cause sql injections.

Much easier to accidentally write something that boils down to

   "\{bobby}" 
where it should have been

   SQL."\{bobby}"
than

   STR."\{bobby}"
instead of

   SQL."\{bobby}"
(i admit that this argument would work better if STR was typographically more different from the name you'd inevitably use for an SQL statement processor)


They want to ensure the new interpolation sequence is a compiler error in non-template strings, so that the incorrect “hi \{name}” is an error instead of silently doing the wrong thing. Using \{ accomplished this because it’s an unknown escape sequence in older Java (so forbidden there), and in new Java will have the more specific error of “yo you forgot the template processor at the start of your template”.


Yes, you do not get a compile time error, but visually a big STR is front is enough "${variable}" vs STR."${variable}"

And editors will use different colors.

Using \ or $ is not about backward compatibility but about ergonomics.


In a word, horrible.

Classic Java though. Take a well established pattern, implement it 10 years late, and somehow make it worse.


Let me ask you a serious question: Given that some people have been claiming that Java is introducing features too late or too badly for 20 years now (and so PHP will surely kill Java off, and if not then certainly Ruby will, and if not then definitely Node.JS), how do you explain that Java remains the most commonly selected language for serious server-side software? I mean, at some point during an exceptionally long success streak in sports, the argument that the team manager doesn't know what he's doing starts to sound silly.

If the argument is along the lines of "the market is stupid," then surely that's something that can be exploited. In fact, that was Paul Graham’s point over 20 years ago in Beating the Averages: if a language is superior then it should confer a market advantage. And yet, that's not happening to Java.

If the argument is about momentum, then after 20 years of "surely this is the last nail in the coffin," clearly there is some misestimate of the importance of various factors.

So to me it looks like either the purported mistakes aren't really mistakes at all, or they are but clearly don't matter much. Is there another possibility?


I think it's wonderful. Some design decisions are odd at first glance, but upon looking at their reasoning I find myself agreeing. I think it'll integrate nicely without causing disruption. I especially love having custom processors.


How is it worse?


This is great. This is an extremely useful feature in most other modern languages.

Why the heck did they make it so verbose, though, in terms of number of required characters?


What do you mean by verbose?


Did you read the JEP?


Programmers read? Nah.

We must viscerally react and show our disdain for this thing in order to be approved of by the group.


> We must viscerally react and show our disdain for this thing in order to be approved of by the group.

I don't think this is where I'm coming from, at all, yet the snark in your response seems like the very thing you're railing against.


Yeah, I did. But maybe I missed something, do you care to elaborate?


How does those `interpolate()` methods reach into the surrounding context to get values of the variables?


They don't, a string template literal is parsed into a StringTemplate object (including the result of evaluating each template fragment), and interpolate() is a method on that.


Interpolate method accesses callsite context to extract values of the variables named in template. How?


I assume it just parses the string templates (at compile-time) and extracts the expressions being templated in, that's not exactly high-flying tech, cpython manages to do it.


Oh, right. The values seem to come from the context of where template was parsed and are kept inside StringTemplate object (.values()).


conveniently left out C++ where it's compile time verified (see std::format), and ofc Rust


This is primarily an interpolation proposal.

AFAIK C++ requires explicit formatting (even if it's compile-time verified), and Rust only has extremely restricted interpolation (you can only interpolate variables, it does not support expressions, and you still have to use formatting macros for interpolation to trigger).


The idea of allowing developers to define their own template formatter falls soundly into the "Thanks, I hate it" category for me. However, in willing to believe we might all be crowing for such power once the shock wears off and Java devs are enjoying their new found power.

On the other hand, the idea of having to know the details of a half-assed, janky, mini-DSL built in a panic by a dev who left six months ago fills me with dread.


Scala had the feature for a while (since 2.10, 2013 I think). Many Scala features have been abused in the wild, this one not so much.

This is mostly useful to library authors, the textbook example being a safe SQL interpolator mentioned in the JEP.


Custom templates is probably the least bad idea of this proposal.

Javascript has had this feature ever since ES6 template strings were introduced and I've yet to see it abused (although I'm sure some folks have). I regularly wish Python's f-strings had custom processors, as it allows creating more convenient safe APIs, instead of having to hunt down idiots who build queries with f-strings because that's more convenient than using the safe-SQL-composition (to say nothing of query builders) they're provided with.


But this makes such DSLs more regular and less ad-hoc than what people are using now, which are completely custom templating engines. If you don't like templating at all that's one thing -- although even non-template-based APIs for constructing things like HTML, SQL, and JSON are no less of a DSL -- but it is already popular in the Java world.


Yep I’m that crunchy dev that thinks this is a lot of ceremony for something pretty useless and will just crowd/uglify a codebase.

I don’t see why this is better than messageformat in any case? I think you might save typing like 6 whole characters? I don’t understand the value at all, perhaps I’m missing something? Just please no ‘it’s prettier’ nonsense.


One of the ugliest implementations I've seen


It's also a powerful one, matched only by few other languages.

I'm happy Java enhancements don't settle for half-baked features, and carefully avoid backwards compatibility issues. Yes the syntax is verbose like that of many recent features (like sealed classes) but honestly given modern tooling, who cares?


It’s a bit weird, they list many syntaxes in many popular programming languages and they somehow ended up with a different monstrosity.


The somehow is explained quite well at the end - they discussed different approaches and why they chose the current one.


Problem is, it's not a good explanation. Almost none of the arguments actually require the given syntax, and they invent problems where there aren't necessarily any, as demonstrated by so many existing languages.


Sadly, true. Why is the template processor named `STR`, why not `f"String"`, like Python? On top of the ugly `STR.` prefix, this dreaded `\` character infuriates me more. Kotlin and Groovy have the nicest implementation by far because it doesn't require any prefixes. I understand Java can't suddenly do that because it needs to be backward-compatible.

I can't get over the ugly `\{someVar}`. It will be easily confused as the `{` character is being escaped, rather than a template. `${someVar}` was a much better option.


> Sadly, true. Why is the template processor named `STR`, why not `f"String"`, like Python?

It looks like the prefix is pluggable so you can use different template processors, STR is just the default:

> STR is a template processor defined in the Java Platform. It performs string interpolation by replacing each embedded expression in the template with the (stringified) value of that expression.

> FMT is another template processor defined in the Java Platform. FMT is like STR in that it performs interpolation, but it also interprets format specifiers which appear to the left of embedded expressions.

> Developers can easily create template processors for use in template expressions.

This is similar to Javascript's `tagged templates`: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe.... Python's f-strings are very much lacking that.

Although I do agree that the syntax, both of the prefix and the interpolation symbol, is awful.


> the ugly `STR.` prefix

STR is not a prefix but simply the name of the variable referencing the receiver (template processor) of the call, i.e. you can do:

    var x = STR;
    x."....";
In Java, making instance method calls requires a receiver to the left of a `.`. Even though template processing has special syntax, it is still a call to an instance method defined by a normal Java interface, and so, as always, requires a receiver. The new syntax here is what's to the right of the `.`; what's to the left is old syntax.

> It will be easily confused as the `{` character is being escaped

It is being escaped, and so reading it as being escaped is the correct and intended understanding. Just like `\n` or `\t`, `\{` means that the next character has a special meaning, as it always does in Java. There was no need to introduce yet another escape sequence; the old one works just fine.


> STR is not a prefix but simply the name of the variable referencing the receiver

That is THE problem. You can use StringBuilder more easily than this ugly thing. When you write code in IDE (I hope so), writing `.append()` is actually easier than this `\{}` dreadful thing.

> It is being escaped, and so reading it as being escaped is the correct and intended understanding. Just like `\n` or `\t`, `\{` means that the next character has a special meaning, as it always does in Java. There was no need to introduce yet another escape sequence; the old one works just fine.

But what about the `}` after the expression? Who/what is escaping that? It should make it clear that this is a special syntax that does some special things. `\` is sort of universal escape character. Putting it in here feels wrong. Again, that's me (along with some other), and you definitely can disagree.


> You can use StringBuilder more easily than this ugly thing. When you write code in IDE (I hope so), writing `.append()` is actually easier than this `\{}` dreadful thing.

How long have you been using string templates? If you've had a bad experience, please report it to the amber-dev list. If it's speculation, I suggest you actually try the feature for a while.

Also, I think you may have misunderstood what this feature actually does (please read the JEP). StringBuilder produces strings, but string templates are most powerful when you're not producing strings (and `append` does enforce sanitisation/escaping). This feature is not string interpolation (although it could also be used for string interpolation as a special case), and its function is completely different from that of StringBuilder. StringBuilder simply cannot do what this feature does regardless of your thoughts about the syntax, which may or may not be formed after actual experience.

> But what about the `}` after the expression? Who/what is escaping that?

You don't need to. `\` in Java means that the next character triggers some special interpretation, and `\{` means that the interpretation mode continues until the `}`. The closing curly bracket should require no more of a special treatment than the characters inside the curly brackets.

> Putting it in here feels wrong.

When you say "feels wrong" do you mean you've tried the feature for a while and ran into problems or that you simply fear that you might?


> Also, I think you may have misunderstood what this feature...

No, I am aware of the differences between StringBuilder and string templating. One of the most common usage is concatenation (e.g. toString() methods). Sometimes it's cleaner to use StringBuilder instead of + operator to do that. And templating will be mostly used for concatenation.

All I am saying is, it could be simpler. I read the full JEP before my first comment. I frequently do Python and did little bit of Kotlin before. I guess that's where all this is coming from.


> And templating will be mostly used for concatenation.

Whether it will or won't, interpolation is not the reason for the feature, so clearly that's not the use case that should be prioritised, especially as it's been recognised as an exceptionally dangerous use-case. The starting point that we must in no way make string interpolation, which is known to be dangerous, any easier than using safer template processors.

This feature was created (among some other reasons) to solve the severe security problems created by string manipulation, not to make string concatenation -- which is already pretty easy -- easier. As the JEP explains, after a lot of thought the decision was not to offer string interpolation as a language feature and go for string templates instead. Saying that the feature doesn't accomplish well the thing it explicitly doesn't try to accomplish is really not saying much about the potential of this feature. Making string interpolation as easy as it could possibly be was not only not a goal of this feature, but the very thing it was designed to avoid given how dangerous that is.

On the other hand, consider that you can now safely embed HTML templates in Java code.

> I frequently do Python and did little bit of Kotlin before. I guess that's where all this is coming from.

In this case, as in many others, we studied what many other languages did, incorporated what's been learnt about code injection vulnerabilities, and did what we believe to be a marked improvement over other languages' features, at least as appropriate for Java's users. You may disagree, but a lot of thought has gone into the design by some of the world's most accomplished language designers as well as user testing, and so I don't think speculation trumps that. If further experience shows that we got it wrong, it can be fixed.


> The new syntax here is what's to the right of the `.`; what's to the left is old syntax.

Absolutely nothing precluded extending the new syntax to swallowing / obviating the `.`.


True, but nothing necessitated it, either. New features are tested by users for a while (and this one has even been a preview feature in a released JDK for some time), and the people who have actually used the feature didn't report that typing `.` was a problem to them. If further experience shows otherwise, then we could allow dropping the dot.

In other words, security vulnerabilities due to string manipulation are a real and pretty serious problem that this feature aims to solve (or, at least alleviate). If the dot character also proves to be a real problem, which it hasn't yet, then that could be solved later.


So weird that of all the choices they decide to use something used as an escape character.


The backslash is unsightly, I agree. Codifying template expression evaluators as a core part of the language, however, is a rational choice. Java is surprisingly foresightful in this regard - it means idioms in the language itself can guide people to getting the common use case of interpolating stuff correct. "STR" for the most prevalent case is perhaps a bit verbose, but at least it's explicit.


Yea, I’m actually a big fan of Java but my immediate reaction to the syntax here was wtf.


There's literally section called `The STR template processor`.


Yeah, but than what was the point? We could've continue to use existing methods.

The goal was getting something clean and friendly. Look at Python for example. Any similar solution would have made it both non-breaking (codes won't compile with unsupported version) and clean.


Over engineered and totally missing the point while further obfuscating the code using it. Java devs will love it!


No, absolutely not! This will be the most hated Java feature to me.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: