Does String extend StringTemplate? (Was: Update on String Templates (JEP 459))
Tagir Valeev
amaembo at gmail.com
Tue Mar 19 12:55:39 UTC 2024
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/2c631935/attachment-0001.htm>
More information about the amber-spec-observers
mailing list