RFR: 8367531: Template Framework: use scopes and tokens instead of misbehaving immediate-return-queries [v29]
Emanuel Peter
epeter at openjdk.org
Fri Nov 14 14:21:35 UTC 2025
On Fri, 14 Nov 2025 13:57:08 GMT, Roberto Castañeda Lozano <rcastanedalo at openjdk.org> wrote:
>> @robcasloz I suppose we could just remove them, they are just a bit of background.
>>
>>> But wouldn't this take us out of the "everything is a token" design again?
>>
>> I don't think so. It just avoids having to do the detour via `let` and hashtags, and would allow the values to go directly into the string. The formatted strings would then be the tokens. So you would end up with fewer tokens: instead of a `let` and the string with the hashtag, you would just have a templated string that injects the variable into it.
>>
>> But of course, the Template Framework provides more than just string formatting: it also has the `fuel` concept, and the `DataName/StructuralName` concept. And for those, we would still need the explicit scoping. Especially for names - those are fundamentally related to scopes, just because Java has "names in scopes".
>>
>>> at least adding some nuance to them.
>>
>> Ok, well let me try that...
>>
>> So I looked for mentions of "string template", and I only found the passage below from `Template.java`. Let me know if there are more that you were thinking about.
>>
>>
>> 159 * Ideally, we would have used <a href="https://openjdk.org/jeps/430">string templates</a> to inject these Template
>> 160 * arguments into the strings. But since string templates are not (yet) available, the Templates provide
>> 161 * <strong>hashtag replacements</strong> in the {@link String}s: the Template argument names are captured, and
>> 162 * the argument values automatically replace any {@code "#name"} in the {@link String}s. See the different overloads
>> 163 * of {@link #make} for examples. Additional hashtag replacements can be defined with {@link #let}.
>> 164 *
>>
>>
>> I think that's still largely accurate now. We need hashtag replacements because we don't have string templating. But that does not mean we would get rid of the Template Framework once we have string templating. Though I suppose we might be able to get rid of hashtag replacements at that point.
>>
>> @robcasloz What do you think: does it still need more nuance? Should I just delete it? Or keep as is?
>
>> So I looked for mentions of "string template", and I only found the passage below from `Template.java`. Let me know if there are more that you were thinking about.
>
> There are a few mentions at TestTutorial.java.
>
>> I think that's still largely accurate now. We need hashtag replacements because we don't have string templating. But that does not mean we would get rid of the Template Framework once we have string templating. Though I suppose we might be able to get rid of hashtag replacements at that point.
>>
>> @robcasloz What do you think: does it still need more nuance? Should I just delete it? Or keep as is?
>
> Thanks for the explanation. I'm still failing to see how one would combine string templates and explicit scoping, but it is good enough for me at this point if you have a clear plan of how it could be done.
@robcasloz
> Thanks for the explanation. I'm still failing to see how one would combine string templates and explicit scoping, but it is good enough for me at this point if you have a clear plan of how it could be done.
Right, it is all quite hypothetical anyway, and I don't think quite relevant to this PR.
But let me still try to explain with some quick example, how it may look like with string template:
var template = Template.make((String arg1, Integer arg2) -> scope(
// Note: no hashtag definition of arg1 and arg2 any more.
// Note: arg1 and arg2 are essecially colocated with the scope of the Template above.
// Now let's use arg1 and arg2 in some templated string:
f"testing {arg1} testing {arg2 + 1} testing\n",
// Above, we could inject variables and even computations into the string, and that produces our first token.
// Now let's define some DataName, and then sample:
addDataName("x", ...),
dataNames(...)....sample((DataName dn) -> scope(
// Note: dn is colocated with the scope of "sample".
"testing {dn.name()} testing {dn.type()} testing\n"
))
));
One concern would probably be that we need a way to define local variables in a scope, so that we can define one value (e.g. randomly generated), and use that exact value multiple times. Maybe that would then still require some modified version of `let`:
let(RANDOM.next(), (Integer x) -> scope(
"testing {x} testing {x} testing",
))
Again: the `scope` would not directly interact with the string templates, but the Template Framework would ensure that they are colocated: local variables are basically only created as lambda arguments that are live for the "scope" of the lambda, which by design of the Template Framework, is colocated with the `scope`s.
I hope that makes some sense and illustrates the alternative we would have with string templates - once they would be available ;)
> There are a few mentions at TestTutorial.java.
Right, good catch. I can find these cases where string templates are mentioned:
159 // It would have been optimal to use Java String Templates to format
160 // argument values into Strings. However, since these are not (yet)
161 // available, the Template Framework provides two alternative ways of
162 // formatting Strings:
163 // 1) By appending to the comma-separated list of Tokens passed to scope().
164 // Appending as a Token works whenever one has a reference to the Object
165 // in Java code. But often, this is rather cumbersome and looks awkward,
166 // given all the additional quotes and commands required. Hence, it
167 // is encouraged to only use this method when necessary.
168 // 2) By hashtag replacements inside a single string. One can either
169 // use "#arg" directly, or use brackets "#{arg}". When possible, one
170 // should prefer avoiding the brackets, as they create additional
171 // noise. However, there are cases where they are useful, for
172 // example "#TYPE_CON" would be parsed as a hashtag replacement
173 // for the hashtag name "TYPE_CON", whereas "#{TYPE}_CON" is
174 // parsed as hashtag name "TYPE", followed by literal string "_CON".
175 // See also: generateWithHashtagAndDollarReplacements2
176 // There are two ways to define the value of a hashtag replacement:
177 // a) Capturing Template arguments as Strings.
178 // b) Using a "let" definition (see examples further down).
179 // Which one should be preferred is a code style question. Generally, we
180 // prefer the use of hashtag replacements because that allows easy use of
181 // multiline strings (i.e. text blocks).
And
207 // Example with hashtag replacements (arguments and let), and $-name renamings.
208 // Note: hashtag replacements are a workaround for the missing string templates.
209 // If we had string templates, we could just capture the typed lambda
210 // arguments, and use them directly in the String via string templating.
This still sounds fine to me. But it is my own writing, so of course it makes sense to me.
Let me know if something specific about it is unclear / misleading for you.
-------------
PR Comment: https://git.openjdk.org/jdk/pull/27255#issuecomment-3532997671
PR Comment: https://git.openjdk.org/jdk/pull/27255#issuecomment-3533012992
More information about the hotspot-compiler-dev
mailing list