Durations in existing JDK APIs

Kurt Alfred Kluever kak at google.com
Wed May 30 16:29:53 UTC 2018


Martin told me know that one or both of the mailing lists ate the HTML
formatting, so it arrived as a mess of plain text. Sorry.

You may have better luck viewing a Google Docs version of my proposal:
https://docs.google.com/document/d/1C-FREsvFmIFibD1ozro6uClYXXA0nssLpg2AoHhQ7DY/edit

On Wed, May 30, 2018 at 10:01 AM Kurt Alfred Kluever <kak at google.com> wrote:

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> *Hi core-libs-dev and concurrency-interest,Recently, we've been closely
> studying date/time code inside of Google, and found a surprising number of
> places with time unit mismatches due to overuse of primitives to represent
> date/time concepts. And unlike "off-by-one" errors, these are often
> "off-by-1000x" or worse...yikes! For internal APIs, we're strongly
> encouraging folks to use the appropriate java.time types (i.e., Duration or
> Instant) because this greatly reduces the occurrence of these
> problems.There are several improvements in the JDK we'd like to propose: 1.
> Rename ALL existing unitless primitive method parameters to include their
> time unit. At Google, we have static analysis tools to detect unit
> mismatches that work based on method names, variable names, etc. However,
> when methods and method parameters are unitless, the only way to know what
> correct units are is to read and understand the javadocs (which our tools
> obviously can't do). Many IDEs also show method signatures with parameter
> names only. There are a handful of examples in the JDK that we'd like to
> update. For example, Object.wait(long timeout) would become
> Object.wait(long timeoutMillis) (or similar). An incomplete list of these
> APIs is included below [1].2. Add a java.time overload to some APIs that
> currently represent date/time concepts using primitives. While static
> analysis helps find errors, ideally people wouldn't have to decompose their
> Duration instances to call these APIs. Adding a Duration overload of each
> of these APIs would remove the need to decompose durations, and would
> encourage developers to plumb durations through more layers of their
> application. The old primitive-accepting APIs would be softly discouraged.
> Note that new default implementations will have to delegate to the existing
> overloads, and will have to choose between losing precision or capping
> large values at e.g. 292 years (for long nanos), but it is hard to imagine
> this being a serious problem in practice for any of them.1. Note: it's
> probably not worth adding Duration overloads to legacy APIs (e.g.,
> java.util.Timer) or low-level APIs (e.g., java.lang.Object.wait()).
> Determining which APIs make the cut is certainly open to discussion.3. Add
> a java.time overload to most APIs that currently accept a <long, TimeUnit>
> pair. Prior to Java8, the recommended advice for accepting a logical
> duration was to use a <long, TimeUnit> pair, as most
> <https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/locks/LockSupport.html#parkUntil-long->
> of java.util.concurrent currently does
> <https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/class-use/TimeUnit.html>.
> Similarly, we've seen unit mismatch bugs with these APIs as well (e.g.,
> future.get(timeout.toNanos(), MILLISECONDS)). Adding a Duration overload
> for each of these APIs would remove the need to decompose durations, and
> would encourage broader Duration adoption. The old APIs would be softly
> discouraged.1. Note: a few of the <long, TimeUnit> APIs are already
> overloaded, which would make this a 2x2 explosion of methods. Whether that
> sort of API explosion is acceptable is certainly open for discussion.2.
> Note: We've already started adding these overloads
> <https://github.com/google/guava/issues/2999> in Guava
> <https://github.com/google/guava/> and have plans to do so across the
> board. Caffeine <https://github.com/ben-manes/caffeine/> has also added
> <https://github.com/ben-manes/caffeine/issues/221> Duration overloads.4.
> Add APIs to convert between TimeUnit and Duration. As users transition to
> the new Duration-centric world, these APIs will come in handy. They will
> also be necessary for overload-implementers. We're proposing
> Duration.of(long, TimeUnit) and TimeUnit.convert(Duration).These
> recommendations, of course, should also apply to new APIs added in the
> future. Note that we are not expressing an opinion at this time on whether
> new APIs should or shouldn't also have a <long, TimeUnit> overload.Of
> course, even comprehensive adoption of Duration in a codebase will not
> eliminate every possible source of unit mismatch bugs. But it would confine
> them to only the places where Durations are created. This would reduce the
> risk in itself, but also makes it much easier for static analyses to detect
> any remaining bugs. It also lowers the cognitive burden faced by every
> developer interacting with logical durations.We realize that these are
> significant changes, so we'd love to hear your thoughts. We'd also be happy
> to work with Martin Buchholz to make these changes.Thanks,-Kurt Alfred
> Kluever(on behalf of the Java Core Libraries Team @ Google)Appendix[1]
> Unitless primitive parameters - Probably worth adding a Duration overload-
> java.lang.Thread.sleep(long millis)- java.lang.Thread.sleep(long millis,
> long nanos)- Note: this API is particularly weird since it accepts millis
> and nanos!- java.lang.Thread.join(long millis)- java.lang.Thread.join(long
> millis, long nanos)- Note: this API is particularly weird since it accepts
> millis and nanos!- java.nio.channel.Selector.select(long timeout)- Probably
> too low level to worry about adding a java.time overloads-
> java.lang.Object.wait(long timeout)- java.lang.Object.wait(long timeout,
> long nanos)- Note: this API is particularly weird since it accepts millis
> and nanos!- java.lang.ReferenceQueue.remove(long timeout)-
> java.util.concurrent.locks.LockSupport.parkUntil(long deadline)- Note: this
> parameter represents milliseconds since epoch (an Instant)-
> java.util.concurrent.locks.LockSupport.parkUntil(Object blocker, long
> deadline)- Note: this parameter represents milliseconds since epoch (an
> Instant)- java.util.concurrent.locks.LockSupport.parkNanos(long nanos)-
> java.util.concurrent.locks.LockSupport.parkNanos(Object blocker, long
> nanos)-
> java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject.awaitUntil(Date)-
> Note: this would be overloaded with an Instant-
> java.util.logging.LogRecord.setMillis(long millis)- "Legacy" APIs that are
> probably not worth adding a java.time overloads-
> java.util.Timer.schedule(TimerTask task, Date firstTime, long period)-
> java.util.Timer.schedule(TimerTask task, long delay)-
> java.util.Timer.schedule(TimerTask task, Date time)-
> java.util.Timer.schedule(TimerTask task, long delay, long period)-
> java.util.Timer.scheduleAtFixedRate(TimerTask task, Date firstTime, long
> period)- java.util.Timer.scheduleAtFixedRate(TimerTask task, long delay,
> long period)- java.sql.Connection.isValid(int timeout)- Note: this
> parameter is in seconds- java.sql.DriverManager.setLoginTimeout(int
> seconds)- Note: this parameter is in seconds- Networking APIs (perhaps not
> worth adding a Duration overload?)- java.net.InetAddress.isReachable(int
> timeout)- java.net.InetAddress.isReachable(NetworkInterface netif, int ttl,
> int timeout)- java.net.URLConnection.setConnectTimeout(int timeout)-
> java.net.URLConnection.setReadTimeout(int timeout)-
> java.net.Socket.setSoTimeout(int timeout)-
> java.net.Socket.connect(SocketAddress endpoint, int timeout)-
> java.net.ServerSocket.setSoTimeout(int timeout)-
> java.net.DatagramSocket.setSoTimeout(int timeout)*
>


-- 
kak


More information about the core-libs-dev mailing list