String Template processors vs Code Reflection?
Clement Cherlin
ccherlin at gmail.com
Tue Mar 19 20:42:38 UTC 2024
String Template syntax is actually already much more convenient. You close
an embedded expression with '}', not '\}', and embedded expressions are
regular Java code, no escaping required. $"foo = \{ "bar" }" is valid, as
are line breaks and comments inside an embedded expression.
Template syntax deliberately does not use '+' for several reasons. You can
already use '+' to join Strings and other objects, implicitly calling
.toString() on the other objects. StringTemplate syntax is intended to be
easier to read and write; $"literal \{object} literal \{object}" is much
nicer than "literal " + object + " literal" + object. Finally, simple
interpolation is far from the only use case of StringTemplates: they are
intended to be passed to methods that convert them into more complex
things, like correctly-escaped SQL, JSON, HTML/XML, etc, and other
arbitrary non-character-based data types. Using '+' would imply eager
direct interpolation, which is not how string templates work.
Cheers,
Clement Cherlin
On Mon, Mar 18, 2024 at 4:30 PM Mikael Sterner <msterner at openjdk.mxy.se>
wrote:
> Thanks for the response, and yes it was code reflection from Babylon I
> referred to, sorry for not being clearer.
>
> Indeed full code reflection would be more powerful. My curiosity how the
> concepts relate was triggered by the fact that if the code reflection is
> limited to snippets with only aggregation (e.g. operator +) and two types
> (fragments and values) it seems to become very similar to string template
> processing:
>
> // Code reflection processor
> processor.apply(@CodeReflection () -> $"foo = " + bar);
>
> // String template processor
> processor.apply($"foo = \{bar\}");
>
> Where $"..." is shorthand for a fragment literal in the code reflection
> case, and (obviously) a string template in the string template case.
>
> For the code reflection case you could in principle offer a shorthand
> $"foo = \{bar\}" to mean the same kind of aggregation as $"foo = " + bar.
>
> And similarly for the string template case it seems you could offer $"foo
> = " + bar as an alternative aggregation syntax, i.e. translate it to the
> same string template as $"foo = \{bar\}".
>
> (I guess in such a world it would be a personal preferences which kind of
> aggregation style you would prefer: the one with fragments and values
> delimited by + or the one with everything inline in one string template
> literal. One advantage of the former would be that string literal values
> wouldn't need escaping, i.e. $"foo = " + "bar" vs $"foo = \{\"bar\"\}", and
> also line breaks could be more naturally inserted between the parts without
> having to use multiline text blocks.)
>
> Yours,
> Mikael Sterner
>
>
> On Mon, Mar 18, 2024, at 19:04, Clement Cherlin wrote:
>
> Oh, I see, you were talking about code reflection from Project Babylon
> https://openjdk.org/projects/babylon/
>
> You asked, "Is the need to process string templates, seen as code snippets
> aggregating static and dynamic strings, just a special case of a more
> general pattern of processing code snippets semi-lazily using custom rules?
> (Such as safe handling of dynamic strings, or contextual operator
> overloading.)"
>
> No, because String Templates are not code snippets, they're simple
> aggregations of strings and other values. Project Babylon deals in code
> snippets. They are related in the sense of making Java more expressive and
> able to deal with various DSLs and embedded expressions of various types,
> but they way they go about it is very different.
>
> Cheers,
> Clement Cherlin
>
> On Mon, Mar 18, 2024 at 8:50 AM Clement Cherlin <ccherlin at gmail.com>
> wrote:
>
> Hi Mikael,
>
> It looks to me like you're talking about a generic macro processor, not a
> string template processor. While that's an interesting idea, I think the
> scope is so much greater than string templates, it would make more sense as
> its own proposal (see https://openjdk.org/jeps/1 and
> https://cr.openjdk.org/~mr/jep/jep-2.0-02.html for details on the JEP
> process).
>
> String templates, as currently designed, do not capture code snippets, but
> values. The value arguments to a template expression are evaluated to
> ordinary objects.
>
> As stated elsewhere, a template object is simply a wrapper for the N
> values and N+1 string fragments of the template expression. The values are
> evaluated just like the parameters of any other Java constructor/method
> call. The source code or bytecode of the expressions that created the
> values is simply not available.
>
> That said, if you want to pass Java code as strings to the template and do
> some magic with the Classfile API (now in preview) at runtime to generate
> code, you can. You can also use an annotation processor (like Lombok) or
> Java compiler plugin (like Manifold) to do all sorts of advanced
> manipulation of source/bytecode at compile time.
>
> Lombok: https://projectlombok.org/
> Manifold: https://github.com/manifold-systems/manifold
>
> Cheers,
> Clement Cherlin
>
> On Fri, Mar 15, 2024 at 11:32 PM Mikael Sterner <msterner at openjdk.mxy.se>
> wrote:
>
> Hi Experts!
>
> What is the relationship between string template processors and code
> reflection, and would it influence the design of string templates and their
> literals?
>
> Is the need to process string templates, seen as code snippets aggregating
> static and dynamic strings, just a special case of a more general pattern
> of processing code snippets semi-lazily using custom rules? (Such as safe
> handling of dynamic strings, or contextual operator overloading.)
>
> Examples:
>
> // String template processor
>
> String table = "foo bar";
> ResultSet r = s.executeQuery("SELECT * FROM \{table\}"); // Escape dynamic
> table names
>
> // Code reflection processors
>
> String table = "foo bar";
> ResultSet r = s.executeQuery(@CodeReflection () -> "SELECT * FROM " +
> table); // Escape dynamic table names
>
> String value = "bar";
> Pattern p = Pattern.compile(@CodeReflection () -> "foo = " + value); //
> Quote dynamic strings
>
> Matrix m = Matrix.eval(@CodeReflection () -> Matrix.diag(1, 2, 3) *
> Matrix.col(2, 3, 4)); // Matrix multiplication
>
> Document d = HTML.compile(@CodeReflection () -> Body.of(Div.of("Hello
> World!"))); // Escape strings
>
> Each such code reflecting processor API defining it's own rules for how to
> handle code snippets, including processing of any raw string templates
> when/if they are added to the language. Other types than String and
> StringTemplate being handled as fits each API, and to the level of type
> safety wanted by the API user. Evaluation being done lazily or eagerly as
> appropriate.
>
> (In the above "@CodeReflection () ->" is short for some syntax allowing
> inline code reflecting snippets, passed to the API processors in a way that
> allows them to reflect on the snippet code.)
>
> Yours,
> Mikael Sterner
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-observers/attachments/20240319/add3b50f/attachment-0001.htm>
More information about the amber-spec-observers
mailing list