StringTemplates deferred evaluation

Brian Goetz brian.goetz at oracle.com
Sun Mar 17 19:45:29 UTC 2024


It depends on how you measure "don't care anything".  Even this, which 
is pretty fast, still creates an object with a list containing { 
hugeObject, expensiveObject }. This is pretty cheap but not necessarily 
free.  (It may be free if the debug() call gets inlined.)

I think for 9x% of the cases, this is entirely cheap enough; for those 
cases where it is not, the old fussy technique of

     if (isDebugLogging)
         logger.debug(...)

will recapture the rest.

On 3/17/2024 3:41 PM, Anatoly Kupriyanov wrote:
> I guess it is not fair to think about it in terms of premature 
> optimization. I am trying to look at it from a logging-framework 
> developer point of view. As a library developer I should give the 
> smallest overhead possible. So library users could safely do
>   LOGGER.debug("Some thing={}, another={}", hugeObject, expensiveObject);
> and don't care about anything at all as debug is usually disabled. So 
> the debug statement could be used even in a tight computation loop 
> without worries. In other words, logger devs could not assume anything 
> about how their framework would be used, but they will fight for the 
> easiest to use api with the fastest performance.
> The idea is that the trace is usually disabled and an app could 
> chew-up gigs of data, but while debugging/investigating, the trace 
> could be temporarily enabled and expected to degrade performance.
>
>
> On Sun, 17 Mar 2024 at 17:36, David Alayachew 
> <davidalayachew at gmail.com> wrote:
>
>     Thank you for the code example. That helps clarify your desired
>     behaviour.
>
>     Ok, if your intent is to have absolutely no garbage collection
>     whatsoever, then yes, my solution does not guarantee that. How
>     much the JIT will help or optimize, I cannot say.
>
>     That said, a String is a "blessed type" in Java. It has a handful
>     of optimizations that are specific to it and it alone. I am
>     actually expecting that StringTemplates will receive at least a
>     small taste of this sort of optimization.
>
>     Furthermore, the cost of creating a StringTemplate is rarely, if
>     ever, the expensive part of the operation. In fact, I am certain
>     it is trivial, if not optimized away like you were asking.
>
>     I won't presume to call this premature optimization -- perhaps
>     your application needs require it. But if so, I would first wait
>     and see (or better yet, calculate!) the performance metrics of
>     these StringTemplates. If they fail to meet your performance
>     needs, then communicate your performance needs to this mailing
>     list, with a hard example (and ideally metrics!) in tow.
>
>     On Sun, Mar 17, 2024 at 1:07 PM Anatoly Kupriyanov
>     <kan.izh at gmail.com> wrote:
>
>         Classically (how it was done a decade or so ago) the logger
>         method would look like:
>         void debug(String template, Object arg1, Object arg2) {
>           if(!enabled) return;
>         writeLog(interpolate(template, arg1.toString(), arg2.toString()));
>         }
>
>         That allows that  if enabled==false, then it will be zero-gc,
>         guaranteed.
>         It even used a lot of overrides with zero args, one arg, two
>         args to avoid ...-ellipsis array allocation. E.g. see
>         https://www.slf4j.org/api/org/slf4j/Logger.html
>
>         There is a C# hacky approach the String Interpolation Handler
>         (
>         https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/interpolated-string-handler
>         ) to use struct (allocated on stack) and magical isEnabled
>         flags to cover logging effectively.
>
>         I don't see how it would be possible to use the StringTemplate
>         to achieve the similar effectiveness, unless there are some
>         good and reliable optimizations in JIT to avoid allocations.
>
>         On Sun, 17 Mar 2024 at 16:41, David Alayachew
>         <davidalayachew at gmail.com> wrote:
>
>             The cost would be no different than evaluating a
>             StringTemplate lazily. Utlimately, log.debug(blah) is
>             still a method call, and therefore, some object is going
>             into the method. Whether we evaluate the StringTemplate
>             lazily or the Supplier<StringTemplate> lazily is largely
>             the same thing.
>
>             Or am I misunderstanding you?
>
>             On Sun, Mar 17, 2024 at 12:28 PM Anatoly Kupriyanov
>             <kan.izh at gmail.com> wrote:
>
>                 But the "() ->" thing is still a runtime object to be
>                 allocated on the heap... or is the JIT smart enough to
>                 always optimize it out?
>
>                 On Sun, 17 Mar 2024 at 16:17, David Alayachew
>                 <davidalayachew at gmail.com> wrote:
>
>                     I feel like that would be on the logging libraries
>                     to provide, not so much the language.
>
>                     Let's say that your problem (as I understand it)
>                     is like this.
>
>                     log.debug("metrics =
>                     \{this.expensiveComputationThatNormallyWouldntRunUnlessYouActivateDebug()}");
>
>                     Sounds to me like the solution is this instead.
>
>                     log.debug(() -> "metrics =
>                     \{this.expensiveComputationThatNormallyWouldntRunUnlessYouActivateDebug()}")
>
>                     So, your logging library just needs to add a new
>                     overload for a Supplier<StringTemplate>, and then
>                     this problem is solved entirely outside of the
>                     language. Log4J and friends are pretty good about
>                     keeping up with new additions, so it should not
>                     take long.
>
>                     I know it's a little less convenient, but doing it
>                     this way helps keep out complexity from the
>                     feature, and only introduces it where necessary
>                     (and it's only necessary at use-site).
>
>                     Would this meet your needs?
>
>                     On Sun, Mar 17, 2024 at 11:15 AM Justin Spindler
>                     <justin.spindler at gmail.com> wrote:
>
>                         I was toying around with the second preview of
>                         StringTemplates and I had a question regarding
>                         their design.  I was wondering if it had been
>                         considered for the embedded expressions to be
>                         evaluated lazily?
>
>                         One of the first use cases that came to mind
>                         when I was exploring StringTemplates is
>                         logging.  That is an extremely common case
>                         where we want to produce a form of
>                         interpolated value, and the current syntax
>                         generally has the same concerns that a
>                         formatted string would, in that the inputs are
>                         removed from where they are defined within the
>                         message format. However, if the log message is
>                         below the log level threshold you generally
>                         don't want to incur the cost of building the
>                         message, including evaluating those embedded
>                         expressions.  Log libraries typically offer a
>                         mechanism to defer evaluation via Suppliers,
>                         but that feels like it would be a challenge to
>                         use within StringTemplate.
>
>                         C# is an example of a language that offers
>                         this functionality via FormattableString,
>                         which gives a method the ability to choose
>                         whether or not to interpret the template or
>                         evaluate the expressions.  That allows logging
>                         below threshold to be more or less a no-op.
>
>
>
>
>                 -- 
>                 WBR, Anatoly.
>
>
>
>         -- 
>         WBR, Anatoly.
>
>
>
> -- 
> WBR, Anatoly.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20240317/1f3f2f2a/attachment-0001.htm>


More information about the amber-dev mailing list