From gavin.bierman at oracle.com Thu Nov 2 00:38:33 2023 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Thu, 2 Nov 2023 00:38:33 +0000 Subject: Draft Spec for Second Preview of Implicit Classes and Instance Main Methods (JEP 463) In-Reply-To: <20231101175845.9702264CBD7@eggemoggin.niobe.net> References: <20231101175845.9702264CBD7@eggemoggin.niobe.net> Message-ID: <36753FED-B229-40F9-822E-C95762D4E918@oracle.com> Dear experts: The first draft of a spec covering JEP 463 (Implicit Classes and Instance Main Methods (Second Preview)) is now available at: https://cr.openjdk.org/~gbierman/jep463/latest/ Feel free to contact me directly or on this list with any comments. Thanks Gavin > On 1 Nov 2023, at 17:58, Mark Reinhold wrote: > > https://openjdk.org/jeps/463 > > Summary: Evolve the Java programming language so that students can > write their first programs without needing to understand language > features designed for large programs. Far from using a separate dialect > of the language, students can write streamlined declarations for > single-class programs and then seamlessly expand their programs to use > more advanced features as their skills grow. This is a preview language > feature. > > - Mark From amaembo at gmail.com Mon Nov 27 17:00:13 2023 From: amaembo at gmail.com (Tagir Valeev) Date: Mon, 27 Nov 2023 18:00:13 +0100 Subject: [string-templates] Simplify custom processor creation Message-ID: Hello! As we expect that people will create custom template processors, we can simplify their lives. First, it could be common to add a finisher transformation to an existing processor. I think that for many purposes it would be enough to use STR processor as a starter, and then create a custom domain object from the resulting string. This could be simplified if we add a method 'andThen' to the Processor interface: default Processor andThen(Function finisher) { Objects.requireNonNull(finisher); return st -> finisher.apply(process(st)); } Second, I think that many processors may want to keep string parts intact but handle embedded expressions in a special way, effectively replacing the default 'String.valueOf' behavior of the standard STR processor. We can provide a way doing this, encapsulating all the ceremony. Something like this: static StringTemplate.Processor withToString(Function toStringFunction) { Objects.requireNonNull(toStringFunction); return st -> { StringBuilder sb = new StringBuilder(); Iterator fragIter = st.fragments().iterator(); for (Object value : st.values()) { sb.append(fragIter.next()); sb.append(toStringFunction.apply(value)); } sb.append(fragIter.next()); return sb.toString(); }; } withToString(String::valueOf) should be equivalent to the STR template (in functionality, not in performance) Now, one can easily build interesting things like: StringTemplate.Processor REGEXP = withToString(obj -> Pattern.quote(obj.toString())).andThen(Pattern::compile); What do you think? With best regards, Tagir Valeev -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Nov 27 17:24:14 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 27 Nov 2023 17:24:14 +0000 Subject: [string-templates] Simplify custom processor creation In-Reply-To: References: Message-ID: I?d like to up-level this discussion a bit from the specific API suggestions, which are of course meant to be evocative examples. The examples here are obviously useful; I can imagine use cases for all of them. I?m a little concerned about adding them as ?point? solutions, though, because I?d have concerns about whether they will work together. Which makes me think that the withToString example might prefer to be an abstract class rather than a combinator, so that if users want to override various things, those will work together. On Nov 27, 2023, at 12:00 PM, Tagir Valeev > wrote: Hello! As we expect that people will create custom template processors, we can simplify their lives. First, it could be common to add a finisher transformation to an existing processor. I think that for many purposes it would be enough to use STR processor as a starter, and then create a custom domain object from the resulting string. This could be simplified if we add a method 'andThen' to the Processor interface: default Processor andThen(Function finisher) { Objects.requireNonNull(finisher); return st -> finisher.apply(process(st)); } Second, I think that many processors may want to keep string parts intact but handle embedded expressions in a special way, effectively replacing the default 'String.valueOf' behavior of the standard STR processor. We can provide a way doing this, encapsulating all the ceremony. Something like this: static StringTemplate.Processor withToString(Function toStringFunction) { Objects.requireNonNull(toStringFunction); return st -> { StringBuilder sb = new StringBuilder(); Iterator fragIter = st.fragments().iterator(); for (Object value : st.values()) { sb.append(fragIter.next()); sb.append(toStringFunction.apply(value)); } sb.append(fragIter.next()); return sb.toString(); }; } withToString(String::valueOf) should be equivalent to the STR template (in functionality, not in performance) Now, one can easily build interesting things like: StringTemplate.Processor REGEXP = withToString(obj -> Pattern.quote(obj.toString())).andThen(Pattern::compile); What do you think? With best regards, Tagir Valeev -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Mon Nov 27 17:33:18 2023 From: james.laskey at oracle.com (Jim Laskey) Date: Mon, 27 Nov 2023 17:33:18 +0000 Subject: [string-templates] Simplify custom processor creation In-Reply-To: References: Message-ID: <9DBEE840-E204-4A64-8813-4323199BD518@oracle.com> I?d recommend using the two argument StringTemplate.interpolate for this sort of use case. Process values as a stream and then feed to StringTemplate.interpolate(fragments, values). static final StringTemplate.Processor HEXER = st -> { List values = st.values() .stream() .map(v -> v instanceof Integer i ? "0x" + Integer.toHexString(i) : String.valueOf(v)) .toList(); return StringTemplate.interpolate(st.fragments(), values); }; public static void main(String... args) { int x = 10, y = 20; System.out.println(HEXER."\{x} + \{y} = \{x + y}"); } 0xa + 0x14 = 0x1e On Nov 27, 2023, at 1:00?PM, Tagir Valeev wrote: Hello! As we expect that people will create custom template processors, we can simplify their lives. First, it could be common to add a finisher transformation to an existing processor. I think that for many purposes it would be enough to use STR processor as a starter, and then create a custom domain object from the resulting string. This could be simplified if we add a method 'andThen' to the Processor interface: default Processor andThen(Function finisher) { Objects.requireNonNull(finisher); return st -> finisher.apply(process(st)); } Second, I think that many processors may want to keep string parts intact but handle embedded expressions in a special way, effectively replacing the default 'String.valueOf' behavior of the standard STR processor. We can provide a way doing this, encapsulating all the ceremony. Something like this: static StringTemplate.Processor withToString(Function toStringFunction) { Objects.requireNonNull(toStringFunction); return st -> { StringBuilder sb = new StringBuilder(); Iterator fragIter = st.fragments().iterator(); for (Object value : st.values()) { sb.append(fragIter.next()); sb.append(toStringFunction.apply(value)); } sb.append(fragIter.next()); return sb.toString(); }; } withToString(String::valueOf) should be equivalent to the STR template (in functionality, not in performance) Now, one can easily build interesting things like: StringTemplate.Processor REGEXP = withToString(obj -> Pattern.quote(obj.toString())).andThen(Pattern::compile); What do you think? With best regards, Tagir Valeev -------------- next part -------------- An HTML attachment was scrubbed... URL: From amaembo at gmail.com Mon Nov 27 17:44:01 2023 From: amaembo at gmail.com (Tagir Valeev) Date: Mon, 27 Nov 2023 18:44:01 +0100 Subject: [string-templates] Simplify custom processor creation In-Reply-To: <9DBEE840-E204-4A64-8813-4323199BD518@oracle.com> References: <9DBEE840-E204-4A64-8813-4323199BD518@oracle.com> Message-ID: Hello, Jim! It's still a lot of ceremony, so if I need this functionality, I would not use it directly and rather create a function like withToString shown above. I'm not sure that there could be another moving part in common applications, other than object->string conversion. Please correct me if I'm wrong. With best regards, Tagir Valeev On Mon, Nov 27, 2023, 18:40 Jim Laskey wrote: > I?d recommend using the two argument StringTemplate.interpolate for this > sort of use case. Process values as a stream and then feed to > StringTemplate.interpolate(fragments, values). > > static final StringTemplate.Processor HEXER = st -> { > List values = st.values() > .stream() > .map(v -> v instanceof Integer i ? "0x" + Integer.toHexString(i) > : String.valueOf(v)) > .toList(); > return StringTemplate.interpolate(st.fragments(), values); > }; > > public static void main(String... args) { > int x = 10, y = 20; > System.out.println(HEXER."\{x} + \{y} = \{x + y}"); > } > > > 0xa + 0x14 = 0x1e > > > > On Nov 27, 2023, at 1:00?PM, Tagir Valeev wrote: > > Hello! > > As we expect that people will create custom template processors, we can > simplify their lives. > > First, it could be common to add a finisher transformation to an existing > processor. I think that for many purposes it would be enough to use STR > processor as a starter, and then create a custom domain object from the > resulting string. This could be simplified if we add a method 'andThen' to > the Processor interface: > > default Processor andThen(Function finisher) { > Objects.requireNonNull(finisher); > return st -> finisher.apply(process(st)); > } > > Second, I think that many processors may want to keep string parts intact > but handle embedded expressions in a special way, effectively replacing the > default 'String.valueOf' behavior of the standard STR processor. We can > provide a way doing this, encapsulating all the ceremony. Something like > this: > > static StringTemplate.Processor withToString(Function toStringFunction) { > Objects.requireNonNull(toStringFunction); > return st -> { > StringBuilder sb = new StringBuilder(); > Iterator fragIter = st.fragments().iterator(); > > for (Object value : st.values()) { > sb.append(fragIter.next()); > sb.append(toStringFunction.apply(value)); > } > > sb.append(fragIter.next()); > return sb.toString(); > }; > } > > withToString(String::valueOf) should be equivalent to the STR template (in > functionality, not in performance) > > Now, one can easily build interesting things like: > > StringTemplate.Processor REGEXP = > withToString(obj -> Pattern.quote(obj.toString())).andThen(Pattern::compile); > > > What do you think? > > With best regards, > Tagir Valeev > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Mon Nov 27 18:11:17 2023 From: james.laskey at oracle.com (Jim Laskey) Date: Mon, 27 Nov 2023 18:11:17 +0000 Subject: [External] : Re: [string-templates] Simplify custom processor creation In-Reply-To: References: <9DBEE840-E204-4A64-8813-4323199BD518@oracle.com> Message-ID: Okay maybe we just need a mapList method. static List mapList(List list, Function mapper) { return list.stream() .map(mapper) .toList(); } interface AndThenProcessor extends StringTemplate.Processor { default StringTemplate.Processor andThen(Function finisher) { Objects.requireNonNull(finisher); return st -> finisher.apply(process(st)); } } static AndThenProcessor withToString(Function toStringFunction) { Objects.requireNonNull(toStringFunction); return st -> StringTemplate.interpolate(st.fragments(), mapList(st.values(), toStringFunction)); } static final StringTemplate.Processor REGEXP = withToString(obj -> Pattern.quote(obj.toString())).andThen(Pattern::compile); public static void main(String... args) { String name = "Jim"; String surname = "Laskey"; System.out.println(REGEXP."\{surname},\s+\{name}|\{name}\s+\{surname}"); } \QLaskey\E, +\QJim\E|\QJim\E +\QLaskey\E On Nov 27, 2023, at 1:44?PM, Tagir Valeev wrote: Hello, Jim! It's still a lot of ceremony, so if I need this functionality, I would not use it directly and rather create a function like withToString shown above. I'm not sure that there could be another moving part in common applications, other than object->string conversion. Please correct me if I'm wrong. With best regards, Tagir Valeev On Mon, Nov 27, 2023, 18:40 Jim Laskey > wrote: I?d recommend using the two argument StringTemplate.interpolate for this sort of use case. Process values as a stream and then feed to StringTemplate.interpolate(fragments, values). static final StringTemplate.Processor HEXER = st -> { List values = st.values() .stream() .map(v -> v instanceof Integer i ? "0x" + Integer.toHexString(i) : String.valueOf(v)) .toList(); return StringTemplate.interpolate(st.fragments(), values); }; public static void main(String... args) { int x = 10, y = 20; System.out.println(HEXER."\{x} + \{y} = \{x + y}"); } 0xa + 0x14 = 0x1e On Nov 27, 2023, at 1:00?PM, Tagir Valeev > wrote: Hello! As we expect that people will create custom template processors, we can simplify their lives. First, it could be common to add a finisher transformation to an existing processor. I think that for many purposes it would be enough to use STR processor as a starter, and then create a custom domain object from the resulting string. This could be simplified if we add a method 'andThen' to the Processor interface: default Processor andThen(Function finisher) { Objects.requireNonNull(finisher); return st -> finisher.apply(process(st)); } Second, I think that many processors may want to keep string parts intact but handle embedded expressions in a special way, effectively replacing the default 'String.valueOf' behavior of the standard STR processor. We can provide a way doing this, encapsulating all the ceremony. Something like this: static StringTemplate.Processor withToString(Function toStringFunction) { Objects.requireNonNull(toStringFunction); return st -> { StringBuilder sb = new StringBuilder(); Iterator fragIter = st.fragments().iterator(); for (Object value : st.values()) { sb.append(fragIter.next()); sb.append(toStringFunction.apply(value)); } sb.append(fragIter.next()); return sb.toString(); }; } withToString(String::valueOf) should be equivalent to the STR template (in functionality, not in performance) Now, one can easily build interesting things like: StringTemplate.Processor REGEXP = withToString(obj -> Pattern.quote(obj.toString())).andThen(Pattern::compile); What do you think? With best regards, Tagir Valeev -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Mon Nov 27 18:38:12 2023 From: james.laskey at oracle.com (Jim Laskey) Date: Mon, 27 Nov 2023 18:38:12 +0000 Subject: [External] : Re: [string-templates] Simplify custom processor creation In-Reply-To: References: <9DBEE840-E204-4A64-8813-4323199BD518@oracle.com> Message-ID: <7AA220A9-BAB1-414E-B468-09FBAFD1F081@oracle.com> That should be System.out.println(REGEXP."\{surname},\\s+\{name}|\{name}\\s+\{surname}"); // double backslash s On Nov 27, 2023, at 2:11?PM, Jim Laskey wrote: Okay maybe we just need a mapList method. static List mapList(List list, Function mapper) { return list.stream() .map(mapper) .toList(); } interface AndThenProcessor extends StringTemplate.Processor { default StringTemplate.Processor andThen(Function finisher) { Objects.requireNonNull(finisher); return st -> finisher.apply(process(st)); } } static AndThenProcessor withToString(Function toStringFunction) { Objects.requireNonNull(toStringFunction); return st -> StringTemplate.interpolate(st.fragments(), mapList(st.values(), toStringFunction)); } static final StringTemplate.Processor REGEXP = withToString(obj -> Pattern.quote(obj.toString())).andThen(Pattern::compile); public static void main(String... args) { String name = "Jim"; String surname = "Laskey"; System.out.println(REGEXP."\{surname},\s+\{name}|\{name}\s+\{surname}"); } \QLaskey\E, +\QJim\E|\QJim\E +\QLaskey\E On Nov 27, 2023, at 1:44?PM, Tagir Valeev wrote: Hello, Jim! It's still a lot of ceremony, so if I need this functionality, I would not use it directly and rather create a function like withToString shown above. I'm not sure that there could be another moving part in common applications, other than object->string conversion. Please correct me if I'm wrong. With best regards, Tagir Valeev On Mon, Nov 27, 2023, 18:40 Jim Laskey > wrote: I?d recommend using the two argument StringTemplate.interpolate for this sort of use case. Process values as a stream and then feed to StringTemplate.interpolate(fragments, values). static final StringTemplate.Processor HEXER = st -> { List values = st.values() .stream() .map(v -> v instanceof Integer i ? "0x" + Integer.toHexString(i) : String.valueOf(v)) .toList(); return StringTemplate.interpolate(st.fragments(), values); }; public static void main(String... args) { int x = 10, y = 20; System.out.println(HEXER."\{x} + \{y} = \{x + y}"); } 0xa + 0x14 = 0x1e On Nov 27, 2023, at 1:00?PM, Tagir Valeev > wrote: Hello! As we expect that people will create custom template processors, we can simplify their lives. First, it could be common to add a finisher transformation to an existing processor. I think that for many purposes it would be enough to use STR processor as a starter, and then create a custom domain object from the resulting string. This could be simplified if we add a method 'andThen' to the Processor interface: default Processor andThen(Function finisher) { Objects.requireNonNull(finisher); return st -> finisher.apply(process(st)); } Second, I think that many processors may want to keep string parts intact but handle embedded expressions in a special way, effectively replacing the default 'String.valueOf' behavior of the standard STR processor. We can provide a way doing this, encapsulating all the ceremony. Something like this: static StringTemplate.Processor withToString(Function toStringFunction) { Objects.requireNonNull(toStringFunction); return st -> { StringBuilder sb = new StringBuilder(); Iterator fragIter = st.fragments().iterator(); for (Object value : st.values()) { sb.append(fragIter.next()); sb.append(toStringFunction.apply(value)); } sb.append(fragIter.next()); return sb.toString(); }; } withToString(String::valueOf) should be equivalent to the STR template (in functionality, not in performance) Now, one can easily build interesting things like: StringTemplate.Processor REGEXP = withToString(obj -> Pattern.quote(obj.toString())).andThen(Pattern::compile); What do you think? With best regards, Tagir Valeev -------------- next part -------------- An HTML attachment was scrubbed... URL: