I've recently proposed another way to implement the templated string/template 
policies but i may not have made it clear why i think the current proposal [1] 
is bad.

First, some vocabulary, a templated string is a string with some unnamed 
parameters that are filled with the result of expressions
by example, if we use ${ expr } as escape sequence to introduce an expression
the code

  var a = 3;
  var b = 4;
  "sum ${ a } + ${ b } = ${ a + b }"

can be decomposed into

  - a string template that can be seen either as a string "sum @ + @ = @" with 
a special character (here '@') denoting a hole for each parameter
    or an array of strings ["sum ", " + ", " = ", ""] indicating the strings in 
between holes.
  - 3 parameters, param0, param1 and param2 initialized respectively with the 
results of the expressions a, b and a + b

Before talking about the current proposal, let's take a look to the way both 
JavaScript and Scala, implement the string interpolation.

For JavaScript [2], you define a function that the template as an array and as 
many parameters you need
  function foo(templateParts, param0, param1, param2) {
    ...
  }

JavaScript uses backticks `` to delimit the templated strings and ${} as escape 
sequence
so
  var a = 3;
  var b = 4;
  foo.`sum ${ a } + ${ b } = ${ a + b }`

is equivalent to

  foo(["sum ", " + ", " = ", ""], a, b, a + b)


In Scala, this mostly works the same way, there is a class StringContext that 
correspond to a templated string and you define the function foo as a method of 
StringContext that takes the parameters (in Scala, you can add methods on an 
already existing class using (abusing of) the implicit keyword).

  implicit class FooHelper(val template: StringContext) {  // adds the 
following methods to StringContext
    def foo(param0: Any, param1: Any, param2: Any) {
      ...
    }
  }

Scala uses quotes "" to delimit the templated string and ${} as escape sequence
so
  val a = 3;
  val b = 4;
  foo."sum ${ a } + ${ b } = ${ a + b }"

is equivalent to
  new StringContext("sum ", " + ", " = ", "").foo(a, b, a + b)



In summary, for both JavaScript and Scala, the generalization of string 
interpolation is a function call which takes the templates string parts as 
first argument and the parameters of the templated string as the other 
parameters.

So in Java, you would assume that
- there is an object that represents a templated string with the holes
- there is a method that takes the templated string as first parameter and the 
parameters of the templated string

But this is not how the proposed design works.

The TemplateString does not represent a string with some holes, it represents 
the string with some holes plus the values of the holes, as if the arguments of 
the parameters were partially applied. The TemplateString acts as a closure on 
the arguments, a glorified Supplier if you prefer.

Because the arguments are already inside the TemplatedString, the 
TemplatePolicy, the function that should take the template and the parameters 
does not declare the types of the parameters.
Which means that there is no way for someone that creates a TemplatePolicy to 
declare the types of the parameters, any parameters is always valid, so there 
is no type safety.

This design is not unknown, this is the GString [4] of Groovy. While it makes 
sense for a dynamic language like Groovy to not have to declare the type of the 
parameters, it makes no sense for a language like Java which is statically 
typed to not have a way to declare the types of the parameters like Scala or 
TypeScript/JavaScript do.

The other issue with the proposed design is that there is no way to declare the 
template policy as a static method, it has to be an instance method 
implementing an interface despite the fact that both JavaScript and Scala* 
support function first and lets the user adds supplementary arguments as a 
secondary mechanism (using currying in Scala and by adding a property on the 
function itself in JavaScript).

There is a good reason to support static methods in Java, a lot of use-cases 
does not requires the template policy to have additional arguments (storing 
them in an instance is not necessary) so forcing the template policy to be 
defined as an instance method means a lot of boilerplate for no good reason.

I hope i've convinced you that the current proposal for string interpolation in 
Java is not the right one.

regards,
RĂ©mi

* for Scala, it's a method on StringContext that acts as a function that takes 
a StringContext as first parameter.

[1] https://bugs.openjdk.java.net/browse/JDK-8273943
[3] 
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
[4] https://docs.scala-lang.org/overviews/core/string-interpolation.html
[2] https://docs.groovy-lang.org/docs/latest/html/api/groovy/lang/GString.html

Reply via email to