Presentation at JCrete.org

David Alayachew davidalayachew at gmail.com
Mon Jul 24 14:33:19 UTC 2023


(looks like Brian beat me to the punch, but I'll respond anyways)

Hello Rémi,

Thank you for your response!

> A call to a template processor is a method call
> (processor) to a Java object (StringTemplate.Processor).
> If we wanted to not have side effect, instead of using a
> OOP design we will have used a functional design, in this
> case a function call with an API closer to a varargs call
> (similar to what JavaScript does).

Who says that OOP demands side-effects? You can write pure functions using
OOP code. The reason why there is a Java Object is to dilineate one
template processor from the other. It's to separate them. But all that does
is make an instance for each processor. No one said that the instances
themselves must have side-effect causing methods. That's false equivalence.

OOP does not imply nor facilitate side-effects any more than functional
code. You mentioned JavaScript. We both know how dangerously easy it is to
perform side-effectual changes using functional code in JavaScript. Being
OOP or Functional has nothing to do with it, and it's false equivalence to
claim otherwise. Side-effects are facilitated by the LANGUAGE, not the
STYLE of the language or the code being written. That's why side-effects
are so much harder to create in something like Haskell as opposed to
JavaScript -- one attaches a screaming siren to every side-effectual change
you make, and the other gives you little to no indication that you've done
so.

Each template processor has its own template, which doesn't change. All it
does is take in the arguments, interpolates them either as pre-configured,
or as the developer configured it to, then returns the specified output.
And since all of the input arguments are just there to construct a larger
object, no side-effects are necessary! It's not until you start trying to
execute log statements that side-effects enter, and that's what I am taking
issue with.

Ultimately, a function is a function. Whatever objects it allocates in its
body are put up for garbage collection at the end of it, as long as it is a
pure function. And that's my point - each instance of the template
processor should strive to only have pure functions. As I said, some
flexibility is understandable in cases of need, but your Logger template
goes wildly out of bounds from that need.

> I believe you have missunderstood how the validation
> works, there is a separation between the validation of
> the structure and the escaping of the values.
> The validation of the structure can be done once while
> the escaping has to be done for each call.

After reading Robbe's comment (and rereading mine), I realize it was a
mistake to use log4j as an example. I was trying to speak way more
generally than everyone else interpreted it to be. I would encourage you to
reread my response to Robbe to better understand what I truly meant.

But in short, my point was, each use site has different validation needs.
And to use the correct terminology here, I mean validating that the value
created after escaping is good and safe. If you make a template processor
that not only creates the output from the given inputs, but also uses that
output to perform a state-changing side-effectual action, then you make it
harder, not easier, to validate that the output generated in the first
place was correct. And since one of the biggest points of this feature is
to make safe-interpolation easy, your example flies in the face of what
this JEP is trying to do. Does that make sense why I am taking so much
issue with your idea?

> For a logger, the validation depends on...

Since I did a poor job with my log4j example, this entire paragraph
addresses something completely orthogonal to my point. I understood from
the beginning how validation and escaping work for Template processors.
However, I picked a poor example with a very unfortunate coincidence.

> The problem of the template processor is not the syntax.
> It's not even the generated bytecode by javac. It's the
> implementation of the bootstrap method (see
> java.lang.runtime.TemplateRuntime) that
>
> - box all the values into a StringTemplate, storing all
>   instances as Object in an array and all primitives as
>   long in an another array, dropping the types nicely
>   propagated by the compiler.
>
>   So all calls using the themplate processor API are slow
>   because of the boxing (the escape analysis is not able
>   to recover this transformation if you take a look to
>   the generated assembly code).

Maybe all of this is true, but this is entirely separate from my point. My
point is about validation.

> - provides no way to do a different validation per
> callsite, so the validation has to done for each call
> (remember validation != escaping).
>
> There is a better API than the template processor API,
> FMT already uses it (StringTemplate.Processor.Linkage),
> but all other template processors can not use it.

Again, I understand how the validation and escaping works.

As for your point here, I feel like you are trying to turn this feature
into something that it is not, and absolutely should not be.

It's fine to criticize the performance and the way that the template
processor handles its internals. But those reasons are not the biggest
reason why a Logger template would be a bad idea. The biggest reason is
because of the side-effects that you are bringing front and center. OOP has
nothing to do with it. You are turning something that can and should be a
pure functional call into some state-modifying and side-effectual, and that
is the core problem with your logger template. That is the entire point I
was trying to make.

Thank you for your time!
David Alayachew
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20230724/b63cc4f4/attachment.htm>


More information about the amber-dev mailing list