Update on String Templates (JEP 459)
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Fri Mar 15 00:49:48 UTC 2024
On 15/03/2024 00:24, Robbe Pincket wrote:
>
> On 14/03/2024 23:44 UTC, Maurizio Cimadamore wrote:
>
> On 14/03/2024 22:36, Robbe Pincket wrote:
>
> (I’m not a big fan of `TEMPLATE"Foo: \{bar}"` either as it’s just so
> much longer than `"Foo: " + bar`)
>
> Note that when I suggested TEMPLATE as a prefix I was
> obviously not being super serious :-)
>
> Let's do a test (bear with me). Let's assume the two
> prefixes were S and T (not saying I like them, just trying them out
> for size). Let's also assume there's no conversion. Then your examples
> become:
>
> ```
>
> String s1 = "test" // still a string literal
>
> StringTemplate st2 = T"test" // allowed, constant strings can be
> implicitly converted to templates
>
> StringTemplate st3 = "Foo: \{bar}" // Simple string template
>
> String s4c = S"Foo: \{bar}" // short for String.of("Foo:
> \{bar}")
>
> ```
>
> I think that's not too bad? (please don't focus too much on
> the letters).
>
> In the sense: the rare cases (st2) has a prefix. And the
> operation we want explicit (s4c) also has a prefix. Everything else is
> fine.
>
> So the difference is that `T` (or something else) has to be used for
> templates without any holes?
>
> To me it feels a bit weird to have a prefix for the special case of a
> hole-less template.
>
Ok. Note that T would be required in that case, but one might also use
it as a visual delimiter: if a template is very long, it might not be
too readable to leave it implicit as to whether the thing in quotes is a
template or not.
>
> I think I saw an argument passing by, saying something along the line
> that `String` and `StringTemplate` are semantically different so
> implicit conversion in either direction would be bad because it would
> be ambigous.
>
> If this `T` idea is based on that, I don't really see why it would be
> that bad. If an API accepts either, I would intuitivly expect that
> passing a string and passing a hole-less template with the same string
> would give me the same result.
>
> Control question #1: does the conversion here change things
> much? Or, are we reaching for conversions just to have something
> "shorter" ?
>
> Control question #2: let's now assume that S and T were
> spelled (String) and (StringTemplate), respectively. How do we feel
> about this?
>
> ```
>
> String s1 = "test" // still a string literal
>
> StringTemplate st2 = (StringTemplate)"test" // allowed, cast from
> constant string to template
>
> StringTemplate st3 = "Foo: \{bar}" // Simple string template
>
> String s4c = (String)"Foo: \{bar}" // allowed, cast from
> template back to String (interpolation)
>
> ```
>
> I think I answered #1. Having the 'T' *just* for the "hole-less"
> template feels a bit odd? I don't you can sell me on #2.
>
Fair enough - I had to ask :-)
>
> If ´(StringTemplate)"test"` and `(String)"Foo: \{bar}"` are valid,
> will the following things work too? `"test" instanceof StringTemplate
> template` and `"Foo: \{bar}" instanceof String str`. The second one
> I'd assume no, the first one is a bit unclear to me.
>
These are questions I raised even in the context of the implicit
conversion you are advocating for: once you add an assignment
conversion, cast comes with it, and with cast, patterns and instanceof.
In other words, that's the price we have to pay for eliminating the T in
the hole-less template in the way you proposed. Casts just make that
trade-off more explicit.
Another thing I don't love about implicit conversion, is that they don't
play with inference too well:
```
List<StringTemplate> ls = List.of("Hello");
```
The above would be an error. The type-variable (X) for List::of is
seeing two different constraints:
* X = StringTemplate (from the target type)
* String <: X (from the argument)
This fails, because we'd infer StringTemplate which is a supertype of
String. Even if we could somehow "convince" inference that
StringTemplate is a valid "more general" type, I see lots and lots of
dragons here:
* inference would have to be careful only to do certain moves if
constant strings are involved
* if we pick StringTemplate, we're basically saying that the method is
applicable by conversion, so in overload step 2. But is this the
overload step we used to pick that candidate in the first place?
Probably not, because String <: X requires only subtyping, not conversion.
Ultimately, implicit conversion would only "kind of work" and will lead
to issues when interacting with generics. While it's tempting to sweep
issues under the rug (after all they do not seem very important for the
examples we're discussing), such compromises have a tendency to bit us
back when feature "grow up" and start playing more with other feature:
any loss of compositionality there costs quite a bit. Which is why I'm
not in love with implicit conversions
Maurizio
> Maurizio
>
> Kind regards
>
> Robbe Pincket
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-observers/attachments/20240315/a2e3095c/attachment-0001.htm>
More information about the amber-spec-observers
mailing list