Does String extend StringTemplate? (Was: Update on String Templates (JEP 459))

Brian Goetz brian.goetz at oracle.com
Tue Mar 19 13:35:47 UTC 2024


I feel your pain!  We walked many of these steps, for many of the same 
reasons.  Each initially-promising approach (subtyping, poly 
expressions, target typing) turned out to have more drawbacks than 
benefits.  But I agree it would be nice if one could just use a string 
literal where a string template is needed -- no one would be confused 
(when it works right.)

On 3/19/2024 8:55 AM, Tagir Valeev wrote:
> Hello!
>
> Thank you for splitting the thread. I think that String is a 
> StringTemplate in the same sense as zero is also a number, identity is 
> also a function, and empty set is also a set. A degenerate case is 
> important for generalization, as you don't have to think about it when 
> it actually appears.
>
> That said, now I have started to doubt this idea. So far I advocated 
> for 'string should be string template', but what I really want is that 
> 'string literal should be string template', which, while similar, is 
> not the same. Indeed, for unification we don't actually need to 
> support non-literal strings.
> It would be interesting to create a subclass of String like 
> StringLiteral, which is constructed only from literals and implements 
> StringTemplate. However, it will be a huge compatibility disaster. 
> Now, my thought goes into some kind of implicit conversion from String 
> literal (and only from literal) to StringTemplate, which was already 
> discussed elsewhere, so the discussion is already far ahead of my 
> thoughts :-)
>
> To conclude, what I really wanted is a uniform way to specify 
> StringTemplate with 0 embedded expressions and StringTemplate with 1+ 
> embedded expressions. E.g., if we require a prefix for all string 
> templates like ST"...", then this desire will be satisfied. If we 
> don't introduce the prefix but can use String literal in every context 
> where StringTemplate literal is possible (like it's in the current 
> preview), then my desire is also satisfied. I see the drawbacks in 
> every solution, so for now I don't have a strong preference.
>
> With best regards,
> Tagir Valeev.
>
>
> On Tue, Mar 12, 2024 at 6:32 PM Brian Goetz <brian.goetz at oracle.com> 
> wrote:
>
>     Splitting off into a separate thread.
>
>     I would like to redirect this discussion from the mechanical
>     challenges and consequences to the goals and semantics.
>
>     If we are considering "String extends StringTemplate", we are
>     making a semantic statement that a String *is-a* StringTemplate. 
>     While I can imagine convincing oneself that this is true "if you
>     look at it right", this sets off all my "self-justification"
>     detectors.
>
>     So, I recommend we step back and examine why we think this is a
>     good idea before we descend into the mechanics.  My suspicion is
>     that this is motivated by "I want to be able to automatically use
>     String where a StringTemplate is desired", and that this seems a
>     clever-enough hack to get there.  (I think we probably also need
>     to drill further, into "why do we think it is important to be able
>     to use String where StringTemplate is desired", and I suspect
>     further that part of it will be "but the APIs are not yet fully
>     equilibrated" (which would be a truly bad reason to give String a
>     new supertype.))
>
>
>
>
>     On 3/12/2024 1:24 PM, Tagir Valeev wrote:
>>     Hello, Maurizio!
>>
>>     Thank you for the detailed explanation!
>>
>>     On Mon, Mar 11, 2024 at 1:16 PM Maurizio Cimadamore
>>     <maurizio.cimadamore at oracle.com> wrote:
>>
>>         Hi all,
>>         we tried mainly three approaches to allow smoother interop
>>         between strings and string templates: (a) make String a
>>         subclass of StringTemplate. Or (b) make constant strings bs
>>         /convertible/ to string templates. Or, (c) use target-typing.
>>         All these approaches have some issues, discussed below.
>>
>>         The first approach is slightly simpler, because it can be
>>         achieved entirely outside of the Java language.
>>         Unfortunately, adding “String implements StringTemplate” adds
>>         overload ambiguities in cases such as this:
>>
>>         |format(StringTemplate) // 1 format(String, Object...) // 2 |
>>
>>         This is actually a very important case, as we predice that
>>         StringTemplate will serve as a great replacement for methods
>>         out there accepting a string/Object… pack.
>>
>>         Unfortunatly, if String <: StringTemplate, this means that
>>         calling format with a string literal will resolve to (1), not
>>         (2) as before. The problem here is that (2) is not even
>>         applicable during the two overload resolution phases (which
>>         is only allowed to use subtyping and conversions,
>>         respectively), as it is a varargs method. Because of this,
>>         (1) will now take the precedence, as that’s not varargs.
>>         While for String::format this is probably harmless, changing
>>         results of overload selection is something that should be
>>         done with care (esp. if different overloads have different
>>         return types), as it could lead to source compatibility issues.
>>
>>     I would still like to advocate for String <: StringTemplate
>>     solution. I think that the overloading is not a big problem.
>>     Simply making String implements StringTemplate will not break any
>>     of existing code because there are no APIs yet that accept the
>>     StringTemplate instance. The problem may appear only when an API
>>     author actually adds such an overload and does this in an
>>     incompatible way with an existing String overload. This would be
>>     an extremely bad design choice, and the blame goes to the API
>>     author. You've correctly mentioned that for String::format this
>>     is harmless because the API is well-designed. We may suggest in
>>     StringTemplate documentation that the API designers should
>>     provide the same behavior for foo(String) and foo(StringTemplate)
>>     when they add an overload.
>>
>>     I must say that we already had an experience of introducing new
>>     interfaces in the hierarchy of widely-used library classes.
>>     Closable got AutoClosable parent, StringBuilder became
>>     comparable, and so on. So far, the compatibility issues
>>     introduced were tolerable. Well, probably I'm missing something
>>     but we have preview rounds just for this purpose: to find out the
>>     disadvantages of the approach.
>>
>>         On top of these issues, making all strings be string
>>         templates has the disadvantage of also considering “messy”
>>         strings obtained via concatenation of non-constant values
>>         string templates too, which seems bad.
>>
>>     I think that most of the APIs will still provide String overload.
>>     E.g., for preparing an SQL statement, it's a perfectly reasonable
>>     scenario to have a constant string as the input. So
>>     prepareStatement(String) will stay along with
>>     prepareStatement(StringTemplate). And people will still be able
>>     to use concatenation. I don't think that the absence of String <:
>>     StringTemplate relation will protect anybody from using the
>>     concatenation. On the other hand, if String actually implements
>>     StringTemplate, it will be a very simple static analysis rule to
>>     warn if the concatenation occurs in this context. If the expected
>>     type for concatenation is StringTemplate, then something is
>>     definitely wrong. Without 'String implements StringTemplate', one
>>     will not be able to write a concatenation directly in
>>     StringTemplate context. Instead, String-accepting overload will
>>     be used, and the expected type will be String, so static analyzer
>>     will have to guess whether it's dangerous to use the
>>     concatenation here. In short, I think that it's actually an
>>     advantage: we have an additional hint here that concatenation is
>>     undesired. Even compilation warning could be possible to implement.
>>
>>     So, I don't see these points as real disadvantages. I definitely
>>     like this approach much more than adding any kind of implicit
>>     conversion or another literal syntax, which would complicate the
>>     specification much more.
>>
>>     With best regards,
>>     Tagir Valeev.
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-observers/attachments/20240319/296767f6/attachment-0001.htm>


More information about the amber-spec-observers mailing list