Java string interpolation feature has been cancelled
mail.openjdk.org
mail.openjdk.org
Brian Goetz is one of the Java language&JDK architects.
https://mail.openjdk.org/pipermail/amber-spec-experts/2024-A...
> In the course of using this feature in the `jextract` project, we did learn quite a few things we didn’t already know, and this was conclusive enough that it has motivated us to adjust our approach in this feature. Specifically, the role of processors is “outsized” to the value they offer, and, after further exploration, we now believe it is possible to achieve the goals of the feature without an explicit “processor” abstraction at all! This is a very positive development.
My Summary:
- nothing to do with the choice of backslash vs dollar. Doubles down on dollar being bad (due to backward and cross compat with other languages)
- original choice to use "Template Processors" misguided, reverses course to StringTemplate Literals
- this requires a new paradigm where APIs now need to explicitly support StringTemplates, instead of relying on the Processor to convert them into Strings as necessary (big leap in my logic here)
- StringTemplates are explicitly still not Strings. This is in line with their "Security Focus First"
- sensitive APIs that depend on StringTemplates should explicitly treat their interpolated results carefully through overloads in a sensitive context.
Obviously I don't know much about the `jextract` project but I can guess 1 possible way this breaks the security concept is if you use the wrong Processor to pass into a Db.query method, for example.
db.query(STR."select * from users where id = \{id};");
This way, you can still do it, but its just much harder to do. Or as an API developer you could deprecate your String overload and insist only on StringTemplate usage from now on. db.query("select * from users where id = \{id};"); // this is compiled as a StringTemplate
db.query("select * from users where id = \"" + id "\""); // this is still a String, and it's still bad, but can be mitigated by deprecating Stringm method
Disclaimer: i haven't done java in nearly 10 years... i just love theorycrafting. So take my contribution with a pinch of salt please :) String str = new String("Hello \{name}");
OR just add a .interpolate() function String str = "Hello \{name}".interpolate(); // verbose
String str = "Hello \{name}".join(); // less verbose, but less representative
OR probably at the bottom of the list of recommendations String str = "Hello \{name}".toString() // matches StringBuilder behaviour
Knowing Java devs, also a non-zero chance it becomes String str = "Hello \{name}".toUnsafeString()
Quoting Brian:> shed to be painted (but please, not right now.).
A sibling comment links to the actual technical discussion and reasoning.
I want Brian et al. to comment more on reddit threads, not less, but this sort of interpretation is a reason for him not to.
It's not cancelled, and it's not even like the Go Generics situation, where the feature was shot down again and again due to endless deflection and bikeshedding. It will most likely make it in next round, which isn't that far in the future.
>They took the time to get them right, but then they did
I'd say thet just took the time to bikeshed, and ended up not with the "right solution", but with a Not-Invented-Here remake of the Generics wheel with bizarre warts.
The feature is very much still in development. However, it's PREVIEW has been postponed.
Maybe it's a bikeshedding situation, but since we are talking about language design and one with a huge instaled base I think this was the best decision since the upside is really not that great compared to the downside.
[0]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
[1]: https://learn.microsoft.com/en-us/ef/core/querying/sql-queri...
(example showcases it better than API spec, C# generally lets you take it further to perform zero-allocation interpolation with custom interpolated handlers if you e.g. want to pass interpolated output into a buffer/stream/etc.)
----
I'll stand by my past point that it was unnecessarily verbose. I'm really glad they're going back to the drawing board with it
Though as they point out the syntax was not really the problem.
The developers should have never tried to boil the ocean: simple Kotlin or Scala style interpolation with overloading `+` for concatenation is the 80% use case here. Yes it doesn’t do everything. But it makes life a lot more ergonomic. And they rejected this solution out of hand! So instead of something useful but not perfect we get nothing.
>Perhaps I can shed some light on this apparent contradiction.
>We discovered, unfortunately quite late in the game, that the design was flawed. How was this discovered? By actually using it in a substantial, real-world internal project. But these flaws had little to do with "someone didn't like the syntax"; they were much more fundamental to the model.
>Unfortunately, most of the feedback we received on public channels was of the "someone didn't like the syntax" variety (at varying levels of constructiveness, not all with positive coefficients). It did not derive from actual experience or from deep analysis; the supporting arguments provided were emotional, not technical; and it merely re-trod, with little new perspective, already-explored ground. It was literally a thousand drive-by, "blink" responses.
>The net effect of this was not only unhelpful, but anti-helpful. I get that every developer has opinions about syntax, and seemingly some fraction of them will literally explode if they don't express it out loud, but such discussions are like an invasive species: they suck up the oxygen that is required for actually useful feedback to survive. (Or maybe the useful feedback was buried in there, but just got lost in all the noise.)
>So the answer to your implied question is that its possible to be both: the feature can be discovered to be flawed, while at the same time the publicly available complaints were "nothing", as you say. It is sad, but possible.
What I still don't like is the, apparently, automatic conversion of strings to templates? It's confusing because it's not clear in the new code how a template is identified. Just because it contains the \() part? But isn't one of the jep goals to allow apis to "allow Java libraries to define the formatting syntax used in string templates"? What if they used the backtick as a way to define a template? So that "abc \(f)" is a string but `abc \(f)` is a template?
This will force developers to explicitly choose which one to use, but since automatic conversion is rejected, I think this is what makes more sense (plus libraries can decide with overloading to admit one, the other, or both).
Being able to do things like evaluate functions and iterate collections inline with HTML templates has allowed me to sidestep a lot of pain over the years.
Every single templating engine supports this. It doesn't need to be built into the core language. Here's an example from JTE [0]:
@import org.example.Page
@param Page page
<head>
@if(page.getDescription() != null)
<meta name="description" content="${page.getDescription()}">
@endif
<title>${page.getTitle()}</title>
</head>
<body>
<h1>${page.getTitle()}</h1>
<p>Welcome to my example page!</p>
</body>
[0] https://jte.gg/#__tabbed_2_1Just saying, kotlin wasn't just a more aesthetically pleasing java, there were some deeper benefits as far as i can tell.
private Map<String, Client> clients;
public Map<String, Client> getClients() {
return clients;
}
public void setClients(Map<String, Client> clients) {
this.clients = clients;
}
Kotlin's approach, where you declare and instantiate a property, and the getter/setter/backing storage are synthesized for you, is vastly preferable to me: public var clients = emptyMap<String, Client>()https://github.com/apache/solr/blob/main/solr/core/src/java/...
I'm a little surprised it was in literally the first place I looked, but I'm not surprised that it was easy to find. "Use private ivars and write getters and setters to encapsulate your state" was probably the second thing that a generation of CompSci students learned in their first programming class, right after "an object is an instance of a class."
Right at the top of the file...
> /* QueryParser.java / / Generated By:JavaCC: Do not edit this line. QueryParser.java */
I'm not claiming you're not going to see properties written out. I'm just saying that's not the majority of code you're going to see and to claim that idiomatic Java is all getters and setters is a bit far fetched.
Here is what I would consider modern idiomatic Java, immutable records and immutable classes that may expose some of their state:
https://github.com/jstachio/jstachio/blob/main/compiler/apt/... https://github.com/jstachio/jstachio/blob/main/compiler/apt/...
Setters are needed in exceedingly rarely circumstances.
Like C (alongside C++) and UNIX, JavaScript and Web, CLR and C#, JVM and Java are designed together, and have first class tooling in all Java IDEs.
My main reason for using it for my personal hobby projects is because I prefer another IDE.
And Kotlin is only supported by IntelliJ, which I admit is a really good ide, but not my favorite.
I am happy to be wrong now though.
Edit, this is a good step forward, here is the list from NetBeans, the "Toyota Hilux" of IDEs and my favorite:
Language Feature Support Status
File type recognition √
Project type
Semantic syntax highlighting √
Formatting √
Braces matching √
Code completion √
Error Hints/Fixes/Suggestions
Code templates
Refactoring
Debugging
At the pace this is moving now I don't know what will stop me from only using Kotlin in the feature.Code completion
Linting
Semantic highlighting
Debugging
Go-to-definition
Signature help
Hover
Formatting
Document symbols
Find references
$ kotlin
Welcome to Kotlin version 1.6.10 (JRE 21.0.1+12-Debian-2)
Type :help for help, :quit for quit
>>> val b=ByteArray(1);
>>> b[0] == 0;
error: operator '==' cannot be applied to 'Byte' and 'Int'
b[0] == 0;
^
$ jshell
| Welcome to JShell -- Version 21.0.1
| For an introduction type: /help intro
jshell> byte[] ba={0}
ba ==> byte[1] { 0 }
jshell> ba[0]==0
$2 ==> true
upd: formatMy message isn't pick one over the other it is that whatever you pick, make sure it isn't a hack that people will regret using.
Java ended up having neither which seems rather extreme.
---
"{warning} backward incompatibility might sneak up and become a horrifying $price to pay."
What's this about?
I however have some PSTD from University times..
But cancelling that ability seems to be what the fuss is about.
Most of the information is in this email: https://mail.openjdk.org/pipermail/amber-spec-experts/2024-A...
ref https://confluence.atlassian.com/security/security-bulletin-...