[
https://issues.apache.org/jira/browse/GROOVY-11947?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18076123#comment-18076123
]
Jefferson H edited comment on GROOVY-11947 at 4/25/26 1:17 AM:
---------------------------------------------------------------
I think these three methods are enough:
{code:java}
long timedNanos(Runnable r)
long timedMillis(Runnable r)
<T> Timed<T> timed(Supplier<T> s){code}
They cover the main use cases without overcomplicating the API. For void
executions, we have the simple and explicit {{nanos}} and {{millis}} variants,
and for richer scenarios we already have {{timed(Supplier)}} which returns both
the result and the duration.
Adding more overloads (like a {{{}Duration{}}}-returning version for
{{{}Runnable{}}}) could introduce unnecessary ambiguity and make the API less
clear.
I’d keep it this way: simple, explicit, and easy to use 👍
was (Author: JIRAUSER313099):
I think these three methods are enough:
long timedNanos(Runnable r)
long timedMillis(Runnable r)
<T> Timed<T> timed(Supplier<T> s)
They cover the main use cases without overcomplicating the API. For void
executions, we have the simple and explicit {{nanos}} and {{millis}} variants,
and for richer scenarios we already have {{timed(Supplier)}} which returns both
the result and the duration.
Adding more overloads (like a {{{}Duration{}}}-returning version for
{{{}Runnable{}}}) could introduce unnecessary ambiguity and make the API less
clear.
I’d keep it this way: simple, explicit, and easy to use 👍
> Add timing utility methods (timed, timedNanos) and Timed record to groovy-jdk
> -----------------------------------------------------------------------------
>
> Key: GROOVY-11947
> URL: https://issues.apache.org/jira/browse/GROOVY-11947
> Project: Groovy
> Issue Type: New Feature
> Reporter: Paul King
> Priority: Major
>
> h3. Summary
> Add a small set of timing utilities to the groovy-jdk as extension methods,
> providing a convenient way to measure the elapsed time of a block of code
> without the caller having to manually record start/end times. Include a
> {{Timed}} record type for returning a result together with its elapsed
> duration.
> h3. Motivation
> Timing a block of code is one of the most common ad-hoc measurements
> developers perform. The current idiom in Groovy is verbose and error-prone:
> {code}
> long start = System.nanoTime()
> def result = computeSomething()
> long elapsedNanos = System.nanoTime() - start
> {code}
> Developers frequently reach for {{System.currentTimeMillis()}} here, which is
> the wrong tool - wall-clock time is not guaranteed to be monotonic and can
> produce negative or wildly incorrect durations when the system clock is
> adjusted (NTP sync, DST, manual change). A built-in utility that uses
> {{System.nanoTime()}} correctly by default steers users toward the right
> primitive.
> h3. Proposed API
> Three additions to the groovy-jdk:
> {{long timedNanos(Closure c)}} - runs the closure and returns the elapsed
> time in nanoseconds. Does not return the closure's result.
> {{long timedMillis(Closure c)}} - same as above but returns milliseconds
> (computed from nanoTime, not currentTimeMillis, so still monotonic).
> {{<T> Timed<T> timed(Closure<T> c)}} - runs the closure and returns a
> {{Timed}} record containing both the result and the elapsed nanoseconds.
> The {{Timed<T>}} type would be a record with:
> {{T result}} - the value returned by the closure
> {{long nanos}} - elapsed time in nanoseconds
> {{Duration getDuration()}} - convenience accessor returning
> {{Duration.ofNanos(nanos)}}
> {{long getMillis()}} - convenience accessor returning {{nanos / 1_000_000}}
> h3. Example Usage
> {code}
> // Just time it
> long elapsed = timedNanos { expensiveOperation() }
> println "took ${elapsed}ns"
> // Time it and keep the result
> def t = timed { computeReport() }
> println "report generated in ${t.millis}ms"
> processReport(t.result)
> // Use the Duration accessor for human-friendly output
> println "took ${timed { loadData() }.duration}"
> {code}
> h3. Implementation Notes
> All three methods must use {{System.nanoTime()}}, not
> {{System.currentTimeMillis()}}. This is the whole point of the utility.
> Exceptions thrown by the closure should propagate unchanged - the utility
> does not swallow or transform them. Timing information is lost in the
> exception case; if users need timing on failure they can use a try/finally
> around {{timedNanos}} themselves.
> The closure runs synchronously on the calling thread. If the closure submits
> asynchronous work without waiting for it, only the submission time is
> measured. This should be documented clearly.
> {{long}} subtraction of two {{nanoTime}} readings handles wraparound
> correctly as long as the interval is under ~292 years, so no special handling
> is needed.
> h3. Location
> These are best placed as extension methods in {{DefaultGroovyMethods}} or a
> dedicated timing extension module. The {{Timed}} record would live alongside
> them.
> h3. Out of Scope
> Benchmarking utilities (warmup, statistical measurement, JIT handling) -
> users who need this should use JMH.
> Async / reactive timing helpers - a separate concern, possibly a future
> enhancement.
> CPU time measurement - {{ThreadMXBean.getCurrentThreadCpuTime()}} has
> different semantics and should not be conflated with wall-clock elapsed time.
> h3. Related
> Complements the existing time-related sugar in groovy-jdk (e.g.
> {{use(TimeCategory)}}, {{Date}} extensions) by adding a primitive for the
> measurement case specifically.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)