----- Original Message ----- > From: "Brian Goetz" <brian.go...@oracle.com> > To: "Remi Forax" <fo...@univ-mlv.fr>, "Jim Laskey" <james.las...@oracle.com> > Cc: "amber-spec-experts" <amber-spec-experts@openjdk.java.net> > Sent: Vendredi 29 Octobre 2021 19:20:20 > Subject: Re: Are templated string embedded expressions "method parameters" or > "lambdas"?
>> For me, "deferred execution" is not the right way to think about the >> sub expressions of a templated string. > > I think there really are two (related) cases here. > > The first (and more common) case is when you provide a formatter object > directly: > > Foo f = F."Hello \{name()}" > > Here, there are several interesting constraints: > > - The template is formatted exactly once, consuming each parameter > expression exactly once (*) > - The timing of consuming the parameter expressions is the same as the > timing of formatting > > Under these constraints, the eager-vs-lazy interpretation doesn't really > matter, because there's no difference in the timing or arity of > expression evaluation. > > The second case is when you are capturing an "unprocessed" template for > later use: > > TemplatedString ts = "Hello \{name()}"; > > Now, there's no guarantee as to whether the template will be processed > at all, or once, or more than once. Again, this only makes a difference > if (a) the expressions have side-effects or (b) the expressions are > "stateful", acting on state that might have changed since capture time, > such as static state, current time, etc. (Which sounds very much like > the things that Streams tells you not to do in behavioral parameters.) > The sad thing is we would rather people not do these things at all, in > which case it makes less of a difference. Do we really need to support the second case at all ? Instead of "Hello \{name()}" it can be written to something like () -> F."Hello \{name()}" piggy backing on the semantics of lambdas instead of inventing a new kind of "lambda but not exactly a lambda" thing. > > Treating expressions as lazy offers real performance benefits for the > case where the template will not be processed at all (as in logging > frameworks); it minimizes the cost of capturing the TS. Treating > expressions as eager is simpler to reason about (though, in the absence > of side effects, doesn't really matter), but creates a two-stage > evaluation where the expressions are evaluated at one point and combined > at another. Performance is a side-effect too. I think the choice between eager and lazy should be reflected in the syntax, if a sub-expression should be evaluated lazily, the expression can be a lambda or a method reference, like GENERATOR."Hello \(Employee::name)" regards, Rémi > > > > *It may not actually be the case that all are consumed exactly once. > Imagine a framework where you can specifiy localized messages in a way > that lets them reorder / reuse parameters; its possible some parameters > need not be evaluated at all. Again, lazy evaluation defers the costs > until they are needed.