Make Duration and FiniteDuration general?

Scala’s Duration and FiniteDuration in scala.concurrent are used pretty ubiquitous in Scala as a general purpose primitive for representing a duration of time, and I don’t see it’s popularity waning, even in the face of java.util.Duration's introduction with Java8.

Yet Duration is still in scala.concurrent and its Scaladoc warns us:

/*
 * '''''This class is not meant as a general purpose representation of time, it is
 * optimized for the needs of `scala.concurrent`.'''''
 */

Would it be out of the question to:

  • Acknowledge that a std lib general purpose Duration would be nice to have?
  • Make scala.concurrent.Duration that general purpose primitive?
    • The code has undergone very few changes since its introduction and none of the changes seem particularly related to concurrency-related specialisations
    • I’m not sure what about it, if anything, makes it unsuitable as a general purpose duration right now; it could just be a matter of removing that comment, and/or adding a link to it in Predef.
4 Likes

What about deprecating it and use java.time.Duration instead ? It would be one less maintenance burden.

1 Like

java.time.duration does not exist for ScalaJS and Scala native, I assume.

For me at least, I use Scala’s duration because it feel way less verbose than java’s alternative. If it got replaced by java’s duration, I’d probably just pull it in as a dependency instead.

1 Like

I don’t think deprecation is a great answer here: for one, the usage numbers and patterns show that devs want a Scala-based Duration and prefer it over java.time.Duration.

Second, having a “native” std lib Duration feels like the way to go. It’s a very common general need and having to use the Java one makes the std feel incomplete; Java obviously has its own, and so does Rust.

+1 as well to @swachter’s mention of ScalaJS+Native being a factor here (though this exists) and agree with @Katrix’s note on ergonomics too.

2 Likes

A long time ago on a mailing list far, far away, there were some long and hard discussions on this very topic: https://groups.google.com/forum/#!searchin/scala-internals/duration|sort:date/scala-internals/MtknlVCYkRc/d71fZvYb98cJ

Please note that the discussion in the thread above was quite heated at times.

2 Likes

I guess the take-away is that an API designed for N use-cases will always be used for at least N+1.

So the question seems to be less, “was Duration originally designed for this?” and more, “a whole lot of people seem to be assuming Duration should do this, is it worth the effort to make Duration suitable to it’s uses?”

1 Like

I don’t.

The java.time package is actually pretty good and I find it easier and better to work with than Scala’s thin alternative. Keep in mind that Scala only has a duration where as in java.time you’ve got a whole ecosystem of temporal utility that all integrates very well with itself. That Scala has just one slice (duration) and nothing else (no Instant, no LocalDateTime, etc) means doing anything more than passing a duration around is a pain when you mix-and-match.

I’d love to see Scala’s duration deprecated, it’s just more needless choice that introduces compatibility problems especially for library authors. I feel like I have to support java.time.Duration and FiniteDuration in my libraries and it’s annoying.

Or maybe there’s a middle ground? For example, if it’s so rage-inducingly critical to some users that they type 20.millis instead of Duration.ofMillis(20) then maybe we could have a Scala DSL to create java.time.Durations?

5 Likes

I’d be all for deprecating scala.concurrent.duration in favor of java.time.

scala.concurrent.duration is a minimal shim dating back to a time when the Java platform did not have a time library. The platform has now moved on and standardized on java.time, and we should get on board

6 Likes

Agreed that java.time plus a slim set of extensions for ergonomics of creation and arithmetic would be preferable to the current situation, but who knows when we can break bincompat and actually do that.

What we (or someone) could do now is create an external library that does that, but all methods and classes that have Duration parameters will have them for the forseeable future. A port of nscala-time from noda to java.time might be just that.

Having the Scala stdlib depend on java.time.Duration would be huge setback for Scala.js. It would mean that we would have to support java.time.Duration in Scala.js core, and with it all the transitive dependencies of java.time.Duration. And that’s a lot!

Today Scala.js core doesn’t need to care about java.time. The java.time package is provided and maintained by contributors who actually care about it, outside of the core. If we have to move this inside the core repo, it will mean a lot more code in the core, maintained by people who don’t care about java.time (understand: me).

That would be disastrous.

6 Likes

If this was only about scala.concurrent.Duration and relatives, then i would have no problem saying, if Scala.js wants it, let them have it.

But if we are going to go further down this road to its logical conclusion that we do not want to use popular and perfectly fine pieces of the Java standard library, just because the Scala.js does not want to support them, and instead we feel we need to reinvent all these wheels in Scala, then Scala.js has become a dangerous liability.

My understanding is that most of the stuff that depends on scala.concurrent.duration already doesn’t work on Scala.js anyway: Await.result or Await.ready, and that’s about it. In particular, most Future stuff don’t rely on durations at all, except when they interface with those blocking APIs. The collections don’t depend on scala.concurrent.duration, neither does most of the core APIs like functions/options/etc. I’ll wager that most user code doesn’t depend on it either.

If that’s the case, not supporting scala.concurrent.duration on Scala.js doesn’t seem like it would have much of an impact on users at all. Scala.js already doesn’t support a bunch of standard library APIs, which is not a problem as long as they aren’t transitively depended on by anything crucial for front-end browser development. For anyone who desperately needs java.time.Duration, there are externally-maintained libraries that provide it to a decent level of fidelity

js.timers.* itself, part of the Scala.js standard library, uses scala.concurrent.duration.

I am pretty sure there’s a bunch of things out there that cross-compile for Scala.js and use scala.concurrent.duration. You can’t build Await, but you can build delays in a portable API using scala.concurrent.duration.

4 Likes

java.time is a huge API, with very hard problems related to the distribution of TZ data and other awful things like that. Everything that the Scala stdlib depends on from the Java stdlib, and which we can support at all, we do support, and we do maintain, and we do fix bugs in them.

But adding java.time in the core repo of Scala.js is just too much.

Today, the Scala.js core repo has about 150 kLoC of .scala code. That’s the compiler, linker, optimizer, and all the JDK APIs that we already reimplement, plus all the tests.

The scala-java-time repo has about 380 kLoC of .scala code. That is more than 2x all of Scala.js.

You’re asking something completely unreasonable from us if you think I’m being lazy and I just “don’t want to support it”.

3 Likes

If we did deprecate FiniteDuration in favor of java’s duration, what would we do about scala’s Duration. Stuff like Duration.Inf? AFAIK, java time doesn’t have anything equivalent of that.

1 Like

I’m not saying Scala.js developers are lazy or anything. I suppose they are not.

But if support for Scala.js creates such limitations to what Scala can do, then Scala.js is a serious liability.

My question is: What is wrong with current state. JVM users have java.time.* if they need… scala.js users don’t have it but who cares (scala.concurrent.Duration is fine for most usecases).

Changing existing, extremely heavily used API is risky, expensive and error prone. It will make harder to cross-compile libraries, and reason for changing is just not worth it.

I think it should stay as it is now … just another opinion.

2 Likes

So the question seems to be less, “was Duration originally designed for this?” and more, “a whole lot of people seem to be assuming Duration should do this, is it worth the effort to make Duration suitable to it’s uses?”

Basically, yes.

I think we should stay on track (this is about s.c.Duration) and not take this discussions to extremes ("we need to replicate all Java java.time.* or std lib things in Scala and the horrible huge burden it imposes).

Since someone brought up LoC, the entirety of s.c.Duration sits in a very well-commented 742LoC file.

Re: @japgolly’s idea

Or maybe there’s a middle ground? For example, if it’s so rage-inducingly critical to some users that they type 20.millis instead of Duration.ofMillis(20) then maybe we could have a Scala DSL to create java.time.Duration s?

It goes a bit beyond that, I think :wink:. s.c.Durations can be compared and added with other Durations as well, Having said that, a thin wrapper around java.time.Duration for the JVM that can be re-implemented quickly for ScalaJs seems acceptable to me.

2 Likes

Why not just move scala.concurrent.Future, along with Duration, out from core library. After all, there are a dozen of alternative libraries for asynchronous programming nowadays.