On 14/03/2024 19:39, Guy Steele wrote:
This is a very important example to consider. I observe, however, that
there are at least two possible ways to avoid the unpleasant surprise:
(1) Don't have string interpolation literals, because accidentally
using a string interpolation literal instead of a string template
literals can result in invoking the wrong overload of a method.
(2) Don’t overload methods so as to accept either a string or a string
template.
I agree with your analysis, but note that there is also a third option:
(3) make it so that both string interpolation literal and string
template literal have a prefix.
I believe that is enough to solve the issue (because the program I wrote
would no longer compile: the compiler would require an explicit prefix).
Maurizio
If we were to take approach (2), then:
(a) We would keep `println` as is, and not allow it to accept a
template, but that’s okay—if you thought you wanted a template, what
you really want is plan old string interpolation, and the type
checking will make sure you don't use the wrong one.
(b) A SQL processor would accept a template but not a string—if you
thought you wanted string interpolation, what you really want is a
template, and the type checking will make sure you don't use the wrong
one.
(c) I think `format` is a special case that we tend to get hung up on,
and I think that, in this particular branch of the design space we are
exploring, perhaps a name other than `String.format` should be chosen
for the method that does string formatting on templates. Possible
names are `StringTemplate.format` and `String.format$`, but I will
leave further bikeshedding on this to others. I do recognize that this
move will not enable the type system per se to absolutely prevent
programmers from writing
|String.format("Hello, my name is %s{name}"); // can you spot the bug? |
but, as Clement has observed, such cases will probably provoke a
warning about a mismatch between the number of arguments and the
number of %-specifiers that require parameters, so maybe overloading
would be okay anyway for `String.format`.
Anyway, my point is that whether to overload a method to accept either
a string or a string template can be evaluated on a case-by-case basis
according to a small number of principles that I think we could
enumerate and explain pretty easily.
—Guy
On Mar 14, 2024, at 1:40 PM, Maurizio Cimadamore
<[email protected]> wrote:
Not to pour too much cold water on the idea of having string
interpolation literal, but I’d like to mention a few points here.
First, it was a deliberate design goal of the string template feature
to make interpolation an explicit act. Note that, if we had the
syntax you describe, we actually achieve the opposite effect: string
interpolation is now the default, and implicit, and actually
/cheaper/ (to type) than the safer template alternative. This is a
bit of a red herring, I think.
The second problem is that interpolation literals can sometimes be
deceiving. Consider this example:
|String.format("Hello, my name is %s{name}"); // can you spot the bug? |
Where |String::format| has a new overload which accepts a StringTemplate.
Basically, since here we forgot the leading “$” (or whatever char
that is), the whole thing is just a big interpolation. Semantically
equivalent to:
|String.format("Hello, my name is %s" + name); // whoops! |
This will fail, as |String::format| will be waiting for an argument
(a string), but none is provided. So:
|| Exception java.util.MissingFormatArgumentException: Format
specifier '%s' | at Formatter.format (Formatter.java:2672) | at
Formatter.format (Formatter.java:2609) | at String.format
(String.java:2897) | at (#2:1) |
This is a very odd (and new!) failure mode, that I’m sure is gonna
surprise developers.
Maurizio
On 14/03/2024 15:08, Guy Steele wrote:
Second thoughts about how to explain a string interpolation literal:
On Mar 13, 2024, at 2:02 PM, Guy Steele<[email protected]> wrote:
. . .
—————————
String is not a subtype of StringTemplate; they are disjoint types.
$”foo” is a (trivial) string template literal
“foo” is a string literal
$”Hello, \{x}” is a (nontrivial) string template literal
“Hello, \{x}” is a shorthand (expanded by the compiler) for
`String.of($“Hello, \{x}”)`
—————————
Given that the intent is that String.of (or whatever we want to call
it—possibly the `interpolation` instance method of class `StringTemplate`
rather than a static method `String.of`) should just do standard string
concatenation, we might be better off just saying that a string interpolation
literal is expanded by the compiler into uses of “+”; for example,
“Hello, \{x}.”
(I have added a period to the example to make the point clearer) is expanded
into
“Hello, “ + x + “.”
and in general
“c0\{e1}c1\{e2}c2…\{en}cn”
(where each ck is a possibly empty sequence of string characters and each ek is
an expression) is expanded into
“c0” + (e1) + “c1” + (e2) + “c2” + … + (en) + “cn”
The point is that, with this definition, “c0\{e1}c1\{e2}c2…\{en}cn” is a
constant expression iff every ek is a constant expression. This is handy for
interpolating constant variables into a string that is itself intended to be
constant.
—Guy