9 ms·
JEP draft: String Templates (Final)
- shortrounddev2 3y agoOne of the ugliest implementations I've seen
- speedgoose 3y agoIt’s a bit weird, they list many syntaxes in many popular programming languages and they somehow ended up with a different monstrosity.
- deleted 3y ago[deleted]
- U1F984 3y agoThe somehow is explained quite well at the end - they discussed different approaches and why they chose the current one.
- ghusbands 3y agoProblem 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.
- ahoka 3y agoOver engineered and totally missing the point while further obfuscating the code using it. Java devs will love it!
- mhosain 3y agoNo, absolutely not! This will be the most hated Java feature to me.
- mhosain 3y agoSadly, 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.
- dariusj18 3y agoSo weird that of all the choices they decide to use something used as an escape character.
- turboponyy 3y agoThe 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.
- prng2021 3y agoYea, I’m actually a big fan of Java but my immediate reaction to the syntax here was wtf.
- masklinn 3y ago> 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/Reference/Template_literals#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.
- hocuspocus 3y agoIt'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?
- deleted 3y ago[deleted]
- floodfx 3y agoI 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 https://github.com/floodfx/undead Sure the syntax isn't "pretty" but understandable and you get used to it like anything else.
- ahoka 3y agoThe whole reason for string interpolation is to have a “pretty” syntax.
- pron 3y agoBut 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).
- bruce343434 3y agoI 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.
- whartung 3y agoThese 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.
- dfinninger 3y ago“\{“ 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/stringinterpolationprotocol https://developer.apple.com/documentation/swift/stringinterp...
- AndrewOMartin 3y agoThe 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.
- hocuspocus 3y agoScala 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.
- masklinn 3y agoCustom 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.
- pron 3y agoBut 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.
- david_allison 3y agoUnpleasantly 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}"
- rthkljlkrj 3y ago[dead]
- wiseowise 3y agoThere's literally two sections explaining why it is the way it is. > String interpolation is dangerous > Can we do better?
- ticklemyelmo 3y agoIt'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.
- wiseowise 3y agoThe approach of defining template processors is definitely better. Moving from unsafe to safe is "just" switching STR to whatever secure processor team writes.
- pron 3y agoThey 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.
- sitta 3y agoThe 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.
- rco8786 3y agoAll super weak arguments IMO. Problems that somehow every other language doesn’t have?
- wiseowise 3y agoSuper weak how? They're quite reasonable and weighed-out.
- marginalia_nu 3y agoOther languages are not attempting to be backwards compatible with Java.
- rco8786 3y agoOne 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.
- marginalia_nu 3y agoFew other languages are as committed to backwards compatibility as Java though.
- david_allison 3y agoC# 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-migration-strategies https://learn.microsoft.com/en-us/dotnet/csharp/nullable-mig...
- scotty79 3y agoHow does those `interpolate()` methods reach into the surrounding context to get values of the variables?
- masklinn 3y agoThey 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.
- scotty79 3y agoInterpolate method accesses callsite context to extract values of the variables named in template. How?
- masklinn 3y agoI 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.
- scotty79 3y agoOh, right. The values seem to come from the context of where template was parsed and are kept inside StringTemplate object (.values()).
- scotty79 3y ago> 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?
- ahtihn 3y agoYes, 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.
- masklinn 3y agoWhich 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.
- scotty79 3y agoI guess they want to force you to choose interpolator. So that you won't implicitly use STR when you should have explicitly use SQL.
- masklinn 3y ago> 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.
- scotty79 3y ago
- acjohnson55 3y agoThis 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?
- wiseowise 3y agoDid you read the JEP?
- voidfunc 3y agoProgrammers read? Nah. We must viscerally react and show our disdain for this thing in order to be approved of by the group.
- acjohnson55 3y ago> 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.
- acjohnson55 3y agoYeah, I did. But maybe I missed something, do you care to elaborate?
- krzyk 3y agoWhat do you mean by verbose?
- rco8786 3y agoIn a word, horrible. Classic Java though. Take a well established pattern, implement it 10 years late, and somehow make it worse.
- krzyk 3y agoHow is it worse?
- pron 3y agoLet 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?
- swsieber 3y agoI 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.
- lionkor 3y agoconveniently left out C++ where it's compile time verified (see std::format), and ofc Rust
- masklinn 3y agoThis 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).
- _old_dude_ 3y agoBoth 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.
- usrusr 3y agoAbout time java introduced escape analysis /s
- _old_dude_ 3y agoSadly escape analysis in Java is weak. In this case, it only works if all the template values do not escape.
- neonsunset 3y agoDoes 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)
- pron 3y ago> 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.
- politelemon 3y agoI 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.
- exabrial 3y agoI 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…
- layer8 3y agoI’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.
- pron 3y agoExcept 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.
- exabrial 3y agoYep 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.
- coldtea 3y agoWould 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?
- krzyk 3y agoHow is it better? Just different, and using dollar sign adds another shift press.
- coldtea 3y ago>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.
- pron 3y ago> 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.
- frankjr 3y agoIt'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/Reference/Template_literals?ref=triplet.fi#tagged_templates https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- jitl 3y agoYes, it’s nice to see features flowing from JavaScript -> Java like tagged template literals, now JavaScript is caught up on things like “class”.
- hyperthesis 3y agoIt'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.
- masklinn 3y agoMultiline strings were added back in Java 15.
- hyperthesis 3y agoAh, 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!
- nikeee 3y agoWhat'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.
- djha-skin 3y ago> 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.
- usrusr 3y agoThe 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".
- usrusr 3y agoInability 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".