<i18n dev> RFR: JDK-8285932 Implementation of JEP 430 String Templates (Preview) [v46]
Chen Liang
liach at openjdk.org
Thu Mar 23 01:52:31 UTC 2023
On Mon, 20 Mar 2023 20:31:46 GMT, Jim Laskey <jlaskey at openjdk.org> wrote:
>> Enhance the Java programming language with string templates, which are similar to string literals but contain embedded expressions. A string template is interpreted at run time by replacing each expression with the result of evaluating that expression, possibly after further validation and transformation. This is a [preview language feature and API](http://openjdk.java.net/jeps/12).
>
> Jim Laskey has updated the pull request incrementally with two additional commits since the last revision:
>
> - Tidy javadoc
> - Rename StringTemplate classes
src/java.base/share/classes/java/lang/StringTemplate.java line 449:
> 447: * statically imported explicitly.
> 448: */
> 449: static final SimpleProcessor<StringTemplate> RAW = st -> st;
Should we omit the modifiers `static final`, which are implicit for all interface fields?
src/java.base/share/classes/java/lang/StringTemplate.java line 455:
> 453: * primary method {@link Processor#process(StringTemplate)} is used to validate
> 454: * and compose a result using a {@link StringTemplate StringTemplate's} fragments and values lists.
> 455: *
Paragraph break intended here?
src/java.base/share/classes/java/lang/StringTemplate.java line 550:
> 548: * SimpleProcessor<JSONObject> jsonProcessor = st -> new JSONObject(st.interpolate());
> 549: * }
> 550: * @implNote The Java compiler automatically imports {@link StringTemplate#STR}
Does this note belong here? And does this come with a rule in the Java Language Specification, which can be linked?
src/java.base/share/classes/java/lang/StringTemplate.java line 592:
> 590: */
> 591: @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
> 592: public sealed interface Linkage permits FormatProcessor {
I fail to see any reason a user would call `linkage`; is there anything that's not covered by `TemplateRuntime::processStringTemplate`? And if users can't use this, this can just be relocated to one of the `jdk.internal` packages.
src/java.base/share/classes/java/lang/StringTemplate.java line 679:
> 677: @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
> 678: @FunctionalInterface
> 679: public interface StringProcessor extends SimpleProcessor<String> {
Just curious, what's the rationale of a `SimpleProcessor` or `StringProcessor` as opposed to:
static <T> TemplateProcessor<T, RuntimeException> simple(Function<StringTemplate, T> function) {...}
static TemplateProcessor<String, RuntimeException> string(Function<StringTemplate, String> function) {...}
which avoids the requirement of specifying the type of the template processor local variable; users can use `var` instead.
src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java line 1051:
> 1049: * @param ptypes list of expression types
> 1050: *
> 1051: * @return {@link MethodHandle}
Suggestion:
* @return the {@link MethodHandle} for concatenation
src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java line 1169:
> 1167: * have an extra {@link String} slot for the result from the previous
> 1168: * {@link MethodHandle}.
> 1169: * {@link java.lang.invoke.StringConcatFactory#makeConcatWithTemplate}
Suggestion:
* {@link #makeConcatWithTemplate}
src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java line 1246:
> 1244: * This method creates a {@link MethodHandle} expecting one input, the
> 1245: * receiver of the supplied getters. This method uses
> 1246: * {@link java.lang.invoke.StringConcatFactory#makeConcatWithTemplateCluster}
Suggestion:
* {@link #makeConcatWithTemplateCluster}
src/java.base/share/classes/java/lang/runtime/Carriers.java line 370:
> 368: */
> 369: private static Map<MethodType, CarrierElements>
> 370: methodTypeCache = ReferencedKeyMap.create(() -> new ConcurrentHashMap<>());
Suggestion:
methodTypeCache = ReferencedKeyMap.create(ConcurrentHashMap::new);
src/java.base/share/classes/java/lang/runtime/Carriers.java line 421:
> 419: */
> 420: protected CarrierObject(int primitiveCount, int objectCount) {
> 421: this.primitives = createPrimitivesArray(primitiveCount );
Suggestion:
this.primitives = createPrimitivesArray(primitiveCount);
src/java.base/share/classes/java/lang/runtime/Carriers.java line 776:
> 774: * @throws IllegalArgumentException if number of component slots exceeds maximum
> 775: */
> 776: static CarrierElements of(Class < ? >...ptypes) {
Suggestion:
static CarrierElements of(Class<?>... ptypes) {
src/java.base/share/classes/java/lang/runtime/Carriers.java line 824:
> 822: private CarrierElements() {
> 823: throw new AssertionError("private constructor");
> 824: }
Suggestion:
src/java.base/share/classes/java/lang/runtime/ReferenceKey.java line 49:
> 47: interface ReferenceKey<T> {
> 48: /**
> 49: * {@return the value of the unwrapped key.}
Suggestion:
* {@return the value of the unwrapped key}
Inline return tag generates a period already.
src/java.base/share/classes/java/lang/runtime/ReferencedKeyMap.java line 127:
> 125: @SuppressWarnings("unchecked")
> 126: static <K, V> ReferencedKeyMap<K, V>
> 127: create(boolean isSoft, Supplier<Map<?, ?>> supplier) {
What prevents this to take `Supplier<Map<ReferencedKey<K>, V>>`? Same for below.
src/java.base/share/classes/java/lang/runtime/StringTemplateImpl.java line 40:
> 38: * <p>
> 39: * Values are stored by subclassing {@link Carriers.CarrierObject}. This allows specializations
> 40: * and sharing of value shapes without creating a new class for each shape.
Just curious, what specific benefits does subclassing offer over having `CarrierObject` as a field? I don't see how a new class is ever created for each shape in that scenario, as shapes are only used to construct the 2 MHs in the factory.
src/java.base/share/classes/java/lang/runtime/StringTemplateImpl.java line 65:
> 63: * {@link java.lang.invoke.CallSite CallSite}.
> 64: */
> 65: private final MethodHandle valuesMH;
I don't think `java.lang.runtime` is a package where final fields are [trusted](https://github.com/openjdk/jdk/blob/91f407d6fe285c44bcc25c1acdf5dc0c43be0172/src/hotspot/share/ci/ciField.cpp#L226), so these method handles might have a performance overhead. However, records appear to be optimized and eligible for inlining.
src/java.base/share/classes/java/lang/runtime/StringTemplateImplFactory.java line 88:
> 86: *
> 87: * @param fragments string template fragments
> 88: * @param type method type
Suggestion:
* @param type method type accepting values' types and returning a StringTemplate
src/java.base/share/classes/java/lang/runtime/StringTemplateImplFactory.java line 169:
> 167: * @return StringTemplate composed from fragments and values
> 168: */
> 169: static StringTemplate newStringTemplate(List<String> fragments, Object[] values) {
I recommend renaming this one and the above methods (taking Object[] for values) `newTrustedStringTemplate` to indicate these two trust the passed values array.
src/java.base/share/classes/java/lang/runtime/TemplateRuntime.java line 204:
> 202: Object[] values
> 203: ) throws Throwable {
> 204: List<Object> asList = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(values)));
Suggestion:
List<Object> asList = List.of(values);
For defensive copy.
Don't think processors are harmed by the null-hostile behavior of these list, for many template implementations already use null-hostile lists.
src/java.base/share/classes/java/lang/runtime/TemplateRuntime.java line 233:
> 231: */
> 232: private static StringTemplate fromArrays(String[] fragments, Object[] values) {
> 233: return StringTemplateImplFactory.newStringTemplate(fragments, values);
Should perform defensive copying for the input arrays, specifically `values` (fragments is passed to `List.of`, which is already safe)
In addition, I recommend renaming methods that don't perform defensive copies to like `ofTrusted`, so we can better avoid such problems.
src/java.base/share/classes/java/util/Digits.java line 68:
> 66: */
> 67: final class DecimalDigits implements Digits {
> 68: private static final short[] DIGITS;
Can add `@Stable` to speed up array element access. Same for below.
src/java.base/share/classes/java/util/FormatProcessor.java line 157:
> 155: Objects.requireNonNull(stringTemplate);
> 156: String format = stringTemplateFormat(stringTemplate.fragments());
> 157: Object[] values = stringTemplate.values().toArray(new Object[0]);
Suggestion:
Object[] values = stringTemplate.values().toArray();
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145500281
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145500568
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145503416
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145582334
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145509343
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145511968
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145520158
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145521984
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145532679
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145528633
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145531061
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145531547
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145533037
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145534263
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145566980
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145555878
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145567708
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145576079
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145577290
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145570455
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145578159
PR Review Comment: https://git.openjdk.org/jdk/pull/10889#discussion_r1145579950
More information about the i18n-dev
mailing list