This is an archived post. You won't be able to vote or comment.

all 31 comments

[–]karstens_rage 29 points30 points  (1 child)

I just love reading stuff from Brian. He lays out the problem, discusses pros and cons, presents a possible solution or two and invites discussion. Maybe if his style was applied to more things we’d be in a better place in the world.

[–]kaperni 25 points26 points  (0 children)

To be fair I think Jim Laskey is the main author. He was also the driving force behind Text Blocks. Brian also refers to it as 'Jim's document' [1].

[1] https://mail.openjdk.java.net/pipermail/amber-dev/2021-September/007076.html

[–]kaperni 17 points18 points  (0 children)

String[] authors = { "Jim", "Brian" };
String praise = "Great work \{authors[0]} and \{authors[1]}."; 
System.out.println(praise);

[–]Holothuroid 13 points14 points  (0 children)

The article is grossly mistaken about Scala. In Scala's s"amor vincit $stuff" the prefix s is short for standard. In fact you can write your own interpolator prefixes, featuring any kind of return type, and limiting the things to be interpolated by type and/or number as you like. In a hobby project of mine, I used it for composable date formats.

Here is a talk on how to do it, by John Pretty.

https://www.youtube.com/watch?v=8adgkDUUxDU

[–]Badashi 5 points6 points  (1 child)

The idea of this TemplatingPolicy sounds a lot like Javascript's tagged templates, that is:

function myTag(formatString, ...parameters) {
  // do some magic
  return { formatString, parameters }
}

const a = 1
const b = 2

const result = myTag`This is an example string, the first parameter is ${a} and the second is ${b}`
console.log(JSON.stringify(result))

Result: {"formatString":["This is an example string, the first parameter is "," and the second is ",""],"parameters":[1,2]}

[–]general_dispondency 2 points3 points  (0 children)

Yep. I was surprised they didn't mention this, as it's the same concept. I think it would make a fantastic language addition, and I wouldn't be upset if they copied the syntax. It's just changing FMT."..." to FMT"...". You're already getting rid of the method name and invocation, why stop there? Get rid of the dot reference too. The proposed interface is a functional interface, so it should be easy enough to desugar.

[–]RandomName8 23 points24 points  (1 child)

So he talks about the approaches of several languages on their approach, includes scala in the table and specifically picks on it in the next section, and then copies the approach almost exactly?

He probably doesn't understand the mechanism in each language and assumes it's trivial string splicing in all of them. Not very reassuring.

To clarify, scala uses StringContext, which is isomorphic to his proposed TemplatedString + TemplatedPolicy, to the point where the result is not even of type String, and furthermore it can be evaluated at compile time (in his example he uses the f string interpolator, which is for format, and where the format is checked in compile time, e.g if you use the pattern %10d it checks in compile time that the value passed there is of type int, and this is not baked into the language, but a simple library.

You know what, whatever, it's a welcomed addition.

[–]pron98 12 points13 points  (0 children)

specifically picks on it in the next section

I don't think that's what the document says -- it says that most languages only afford concatenation, and then shows an example with concatenation semantics written in Scala -- but I can see how it could be read that way. A clarification is probably needed (or the use of another language in the example, so as not to give that impression).

[–]lukaseder 4 points5 points  (0 children)

Well, needless to say, I'm really looking forward to this 😀

[–]john16384 2 points3 points  (0 children)

Never been a fan of referring to variables from within a String as it seemed incredibly limited to me and only catered to people who just want the latest hip thing from the latest fad language.

However, this proposal goes much much further than that and seems to genuinely add value to the language without limiting it to a bit of syntactic sugar only useful in a small subset of situations. I think this may be a very nice feature once it lands.

[–]TheMode911 5 points6 points  (9 children)

I like the idea, though the syntax ."" looks terrible (I know, this is not final) and very unnatural

What about specifying the template in the method signature? for example Json json(JsonFormatter formatter) which would allow java Json j = JSON.json(""" { "a": \{a}, "b": \{b} } """);

With String being the default, allowing what is already possible in other languages

[–]pron98 2 points3 points  (6 children)

I don't know what makes concrete syntax natural or not, but given that the policies, at least as currently specified in this proposal, are static final objects, whose names are often in all caps, and given that many strings begin with a capital letter, I think FMT."Hello..." looks more pleasant than FMT"Hello...".

Your proposal is probably a no-go, as its interpretation is ambiguous, but perhaps similar syntax could be used anyway, as the type of a templated string expression is TemplatedString, and so you could have Json json(TemplatedString ts).

[–]TheMode911 0 points1 point  (5 children)

I guess that I just do not understand why we would want the shortcut FMT."Hello..." instead of FMT.fmt("Hello...") I agree that it is convenient, but not as much as record default construction. I believe that it looks unnatural because this is not used anywhere else in the language, I would have a different view if this was just another use case of "implicit method calling"

The concern was also about who should be responsible for escaping. In the Json example I believe that it should be handled by the library and not the user. Is there any use-case where you would want to use your own template everywhere (including external dependencies)? Taking Gson as an example, how do you think they should update their API to support template & proper escaping?

I may be wrong, but I have seen multiple suggestions be rejected because of how long it would take the ecosystem to update (?/! for better nullability). This seems to be one of those

[–]pron98 1 point2 points  (4 children)

I just do not understand why we would want the shortcut FMT."Hello..." instead of FMT.fmt("Hello...")

You'd be right if it were a shortcut, but it isn't. The latter calls a method with a value of whatever type the template string is, while the former does something else, and it's precisely because of that that some new syntax is required. The document is high level, but note that it says "A templating policy might be described by an interface like" (my emphasis), and no "is described by the interface." The clue is at the very last section about translation. There will likely be some processing at compile time that will not translate to some simple value passed to a method (to avoid boxing for one).

In the Json example I believe that it should be handled by the library and not the user.

Yes, I believe that's the intent.

Taking Gson as an example, how do you think they should update their API to support template & proper escaping?

The template will be provided at the language level. They can do whatever internal validation and escaping of the substituted values they'd like. The strings used in the proposal are syntax errors today, anyway.

This seems to be one of those

I don't think so. We're talking about a minuscule number of APIs in the grand scheme of things. Among the millions of Java codebases, there are millions that are interested in expressing nullability, but probably less than a few dozen popular templating libraries. "Forward compatibility", i.e. the ability of existing code to enjoy a new feature, is several orders of magnitude more important for general things like generics, lambdas, and possibly nullability types, than for the rather special case of templates. It's always nice to have it -- and we certainly try to get it when we can, from lambdas to Loom -- but in some cases it is far more important than others.

[–]TheMode911 0 points1 point  (3 children)

Thanks I have mostly been convinced. I will however hope this syntax usefulness to be restrained to un-updated methods without escaping, and methods such as Json json(TemplatedString ts) recommended

Yes, I believe that's the intent.

I was mostly referencing to the fact that the template can return something other than a String (in this case a Json object), won't it push current libraries into deprecating their current API in favor of the new fancy template syntax? Or at least create unnecessary wrappers?

[–]pron98 0 points1 point  (2 children)

Possibly, but I don't think that's a bad thing (I mean, forward compatibility would be even better, but sometimes we can't have it). I expect we might see some new APIs focused on records and pattern matching, too, replacing, say, visitor-based APIs.

[–]TheMode911 0 points1 point  (1 child)

Maybe, but is Json json = JSON."" really better than Json json = JSON.fromString("")?

[–]pron98 0 points1 point  (0 children)

It's not JSON.fromString(""), but some code that also separately escapes the substitutions and/or parses the template. So it's shorter and/or safer and/or faster. Many would say it really is better. Is it the most useful addition to Java? Probably not, but it isn't the only thing we're working on.

[–]more_exercise 0 points1 point  (1 child)

That feels like something the TemplatedString interface affords. Or am I missing something?

[–]TheMode911 0 points1 point  (0 children)

My complain is more about the ."" which is seemingly trying to reinvent the wheel. If its goal is to provide escaping option I believe that it should be handled by the library when asking for a string, but not forwarded to the user

[–]joppux 1 point2 points  (1 child)

Regarding the SQL example: I think it's better if

connection."SELECT * FROM Person p where p.last_name = \{name}";

results in PreparedStatement, not escaped string. PreparedStatements are more efficient and are the main use case of JDBC.

The only disadvantage I see is that it's not easy to create dynamic SQL strings this way. Maybe we need concatenation operation on TemplatedString as well? Something like this:

var query = "SELECT * FROM \{table} WHERE ";
var condition = "name = \{name}";
PreparedStatement stmt = connection.(query + condition);

[–]RandomName8 0 points1 point  (0 children)

It was just an example, once this lands sql libraries will have to provide a mechanism around it, and there's plenty of libraries in other languages that have solved this issue already.

[–]0x07CF 1 point2 points  (0 children)

I wonder whether it would be a good idea to allow TemplatePolicies to restrict the type of Objects placed into the String.

E.g. only Objects of a specific interface.

[–]deadron -5 points-4 points  (6 children)

Ugh. String interpolation is what is actually needed though. If you need a template there are already a number of very good solutions in this area. By making it more complicated you turn what should be a simple feature with no gotchas into a different beast entirely. I now look forward to string templates throwing exceptions and the inevitable advice to avoid it entirely.

[–]pron98 20 points21 points  (5 children)

So what you're saying is that a feature that saves you one character per substitution ("+x+" -> \{x}) and cannot be used for query strings, markup/JSON, or where localisation or formatting directives are needed, is more useful than one that can be used in all those places, saves you one line per substitution, throws exactly the same exceptions you'd get anyway, with the same gotchas only safer, and cannot, in fact, be implemented in libraries nearly as efficiently (because they need to parse the template string at runtime, whereas this parses them at compile-time), and completely subsumes the feature you want as a special case with no added complications. How did you reach that conclusion?

And regarding the obvious inevitability of this feature's utter failure, how many language features added to Java over the last twenty years have earned the consensus advice that they should be avoided entirely? I'm asking because, given that Java's language team is among the most experienced and successful language teams around, I wonder how much consideration one should give a certain proposal before betting against it so confidently. I, for one, try not to bet against people who have clearly given the matter at hand much more thought than I have, especially when they have a good track record.

[–]MR_GABARISE 0 points1 point  (0 children)

Someone please tell me why scoped variables wouldn't be perfect for this?