Are templated string embedded expressions "method parameters" or "lambdas"?
Remi Forax
forax at univ-mlv.fr
Fri Oct 29 16:53:23 UTC 2021
> From: "Jim Laskey" <james.laskey at oracle.com>
> To: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Sent: Vendredi 29 Octobre 2021 16:10:54
> Subject: Are templated string embedded expressions "method parameters" or
> "lambdas"?
> For our early templated string prototypes , we restricted embedded expressions
> to just basic accessors and basic arithmetic. The intent was to keep things
> easy to read and to prevent side effects . Over time, we began thinking this
> restriction was unduly harsh. More precisely, we worried it that it would
> result in a complex, difficult-to-defend boundary. But we still would like
> users to not rely on side-effects.
> Consequently, a new proposal for embedded expressions - we would allow any Java
> expression with the restriction that you can't use single quotes, double quotes
> or escape sequences. We opted to keep this restriction to allow tools (ex.,
> syntax highlighters) to isolate embedded expressions within strings without
> requiring sophisticated parsing.
> Given that an unprocessed templated string involves at least some deferred
> evaluation, should we frame templated string parameters as being more like
> method parameters (all parameters evaluated eagerly, left to right), or should
> we treat them as lambda expressions, which may capture (effectively final)
> variables from the environment, and evaluate the full parameters expressions
> when they are needed?
> Note too that the effectively final restriction rules out some of the worst
> side-effect offenders, like:
> int x = 0;
> formatter."One \{x++} plus two \{x++} is three \{x}";
> -- even if we intend to then do eager evaluation!
> To help understand the issue, let's look at a simplification of how the two
> different paradigms ( method parameter vs. lambda) might be implemented.
> Example:
> int x = 0;
> int method1() {
> System.out.println("one");
> return 1;
> }
> int method2() {
> System.out.println("two");
> return 2;
> }
> System.out.println("Before TemplatedString");
> TemplatedString ts = "\{x} and \{method1()} and \{method2()}";
> System.out.println("After TemplatedString");
> System.out.println(CONCAT.apply(ts));
> System.out.println("After Policy");
Here, i suppose there is a typo, "CONCAT" should be "formatter".
The whole point of the syntax is that you can not introduce side effects in between the reification of the templated string to an object and the method call
so from the POV of the user, there is only one semantics.
> To help us evaluating the tradeoffs between the two paradigms, our question to
> the experts is, " What are the ramifications of each ? " Please resist the
> temptation to express a preference for one or the other.
For me, "deferred execution" is not the right way to think about the sub expressions of a templated string.
After all, a guard of a pattern is also a sub expression and we require the local variables to be captured, despite the fact that there is no "deferred execution".
We do not want side effects in the guard of a pattern, we can not fully guaranteed that in Java but at least we can guarantee that the local variable will not change.
I think the same argument apply to a sub expression of a templated string, we do not want side effect in it, so we should ask the local variables used inside a sub expression to be effectively final.
> Thank you.
> Cheers,
> -- Jim
regards,
Rémi
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20211029/36fbc3a9/attachment.htm>
More information about the amber-spec-experts
mailing list