Is there an elegant way to convert java.time.Duration to scala.concurrent.duration.FiniteDuration?
I am trying to do the following simple use of Config in Scala:
val d = ConfigFactory.load().getDuration("application.someTimeout")
However I don't see any simple way to use the result in Scala.
Certainly hope the good people of Typesafe didn't expect me to do this:
FiniteDuration(d.getNano, TimeUnit.NANOSECONDS)
Edit: Note the line has a bug, which proves the point. See the selected answer below.
I don't know whether an explicit conversion is the only way, but if you want to do it right
FiniteDuration(d.toNanos, TimeUnit.NANOSECONDS)
toNanos will return the total duration, while getNano will only return the nanoseconds component, which is not what you want.
E.g.
import java.time.Duration
import jata.time.temporal.ChronoUnit
Duration.of(1, ChronoUnit.HOURS).getNano // 0
Duration.of(1, ChronoUnit.HOURS).toNanos // 3600000000000L
That being said, you can also roll your own implicit conversion
implicit def asFiniteDuration(d: java.time.Duration) =
scala.concurrent.duration.Duration.fromNanos(d.toNanos)
and when you have it in scope:
val d: FiniteDuration = ConfigFactory.load().getDuration("application.someTimeout")
Starting Scala 2.13, there is a dedicated DurationConverter from java's Duration to scala's FiniteDuration (and vice versa):
import scala.jdk.DurationConverters._
// val javaDuration = java.time.Duration.ofNanos(123456)
javaDuration.toScala
// scala.concurrent.duration.FiniteDuration = 123456 nanoseconds
I don't know any better way, but you can make it a bit shorter:
Duration.fromNanos(d.toNanos)
and also wrap it into an implicit conversion yourself
implicit def toFiniteDuration(d: java.time.Duration): FiniteDuration = Duration.fromNanos(d.toNanos)
(changed d.toNano to d.toNanos)
There is a function for this in scala-java8-compat
in build.sbt
libraryDependencies += "org.scala-lang.modules" %% "scala-java8-compat" % "0.9.0"
import scala.compat.java8.DurationConverters._
val javaDuration: java.time.Duration = ???
val scalaDuration: FiniteDuration = javaDuration.toScala
Related
I want to parse the following JSON object using Scala:
val result = """{"24h_volume_usd": "9097260000.0"}"""
normally I use:
import net.liftweb.json._
case class VolumeUSDClass(24h_volume_usd:String) //<- problem 24h_volume_usd does not work
val element = parse(result)
element.extract[CryptoDataClass]
The problem is that I cannot define a case class with an argument that starts with a number. what is the best way to circumvent this?
You can simply enclose the name of the variable into backticks:
implicit val formats = net.liftweb.json.DefaultFormats
val result = """{"24h_volume_usd": "9097260000.0"}"""
import net.liftweb.json._
case class VolumeUSDClass(`24h_volume_usd`:String)
val element = parse(result)
val vusdcl = element.extract[VolumeUSDClass]
println(vusdcl)
Recall that almost everything can be transformed into a valid Scala identifier if you enclose it in backticks. Even strange stuff like
val `]strange...O_o...stuff[` = 42
println(`]strange...O_o...stuff[`)
works.
The example is tested with "net.liftweb" %% "lift-json" % "3.2.0" and Scala 2.11.
I have found an example code for a Scala runtime scripting in answer to Generating a class from string and instantiating it in Scala 2.10, however the code seems to be obsolete for 2.11 - I cannot find any function corresponding to build.setTypeSignature. Even if it worked, the code seems hard to read and follow to me.
How can Scala scripts be compiled and executed in Scala 2.11?
Let us assume I want following:
define several variables (names and values)
compile script
(optional improvement) change variable values
execute script
For simplicity consider following example:
I want to define following variables (programmatically, from the code, not from the script text):
val a = 1
val s = "String"
I want a following script to be compiled and on execution a String value "a is 1, s is String" returned from it:
s"a is $a, s is $s"
How should my functions look like?
def setupVariables() = ???
def compile() = ???
def changeVariables() = ???
def execute() : String = ???
Scala 2.11 adds a JSR-223 scripting engine. It should give you the functionality you are looking for. Just as a reminder, as with all of these sorts of dynamic things, including the example listed in the description above, you will lose type safety. You can see below that the return type is always Object.
Scala REPL Example:
scala> import javax.script.ScriptEngineManager
import javax.script.ScriptEngineManager
scala> val e = new ScriptEngineManager().getEngineByName("scala")
e: javax.script.ScriptEngine = scala.tools.nsc.interpreter.IMain#566776ad
scala> e.put("a", 1)
a: Object = 1
scala> e.put("s", "String")
s: Object = String
scala> e.eval("""s"a is $a, s is $s"""")
res6: Object = a is 1, s is String`
An addition example as an application running under scala 2.11.6:
import javax.script.ScriptEngineManager
object EvalTest{
def main(args: Array[String]){
val e = new ScriptEngineManager().getEngineByName("scala")
e.put("a", 1)
e.put("s", "String")
println(e.eval("""s"a is $a, s is $s""""))
}
}
For this application to work make sure to include the library dependency.
libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value
I've found this interesting behaviour in nscala_time package (scala version of joda-time)
import com.github.nscala_time.time.Imports._
import com.github.nscala_time.time.DurationBuilder
object tests {
val x = 3 seconds
//> x : is of type com.github.nscala_time.time.DurationBuilder
val xx: DurationBuilder = 3 seconds
//> fails to compile:
// class DurationBuilder in package time cannot be accessed in package com.github.nscala_time.time
}
What I'm trying to achieve is implicit conversion from nscala_time Duration to scala.concurrent.Duration
I need this becuase I'm using RxScala and nscala_time in one application.
// e.g. the following should be implicitly converted
// to nscala_time Duration first
// than to scala.lang.concurrent.Duration
3 seconds
nscala_time offers rich time & date api for my application, while I'm using RxScala in the same class for GUI responsivness.
You can download a simple project to play around: https://dl.dropboxusercontent.com/u/9958045/implicit_vs_private.zip
From scala-user group: It's a known issue https://issues.scala-lang.org/browse/SI-1800
perhaps you can use an implicit conversion? (btw Duration in nscala is essentially org.joda.time.Duration):
scala> import com.github.nscala_time.time.Imports._
import com.github.nscala_time.time.Imports._
scala> implicit class DurationHelper(d:org.joda.time.Duration) {
| def toScalaDuration = scala.concurrent.duration.Duration.apply(d.getMillis,scala.concurrent.duration.MILLISECONDS)
| }
defined class DurationHelper
scala> val d = RichInt(3).seconds.toDuration
// toDuration method is defined for com.github.nscala_time.time.DurationBuilder
d: org.joda.time.Duration = PT3S
scala> def exfun(d:scala.concurrent.duration.Duration) = d.toString
exfun: (d: scala.concurrent.duration.Duration)String
scala> exfun(d)
res41: String = 3000 milliseconds
(not using import scala.concurrent.duration._ here to avoid name clashes with joda/nlscala stuff)
I have an conf/application.conf setting like
mongodb.replicaSetSeeds = ["bobk-mbp.local:27017","bobk-mbp.local:27018"]
I'm pulling it out in my code like (the actual extraction is a little different, but this is the gist of it)
val replicaSetSeeds = Play.current.configuration.getStringList("mongodb.replicaSetSeeds")
val listOfString: List[String] = replicaSetSeeds.getOrElse(List("localhost"))
but the compiler hates me
type mismatch; found : Object required: List[String]
The signature of getStringList is
def getStringList(path: String): Option[java.util.List[String]]
How do I handle the None case here or is my problem List[String] is not the same as List[java.util.String]?
Give this a shot:
import collection.JavaConversions._
val optList:Option[List[String]] = Play.current.configuration.getStringList("mongodb.replicaSetSeeds").map(_.toList)
val list = optList.getOrElse(List("localhost"))
There are multiple things going on here. First, you need to import the JavaConversions implicits because what's being returned is an Option[java.util.List[String]] and we want that to be a scala List instead. By doing the map(_.toList), I'm forcing the implicit conversion to kick in and get me an Option[List[String]] and from there things are pretty straight forward.
In play 2.5, you need to use dependency injection, the following works well for me:
1) in your class inject Configuration
class Application #Inject()(
configuration: play.api.Configuration
) ...
2) in your method
import scala.collection.JavaConversions._
val optlist = configuration.getStringList("mongodb.replicaSetSeeds").map{_.toList}
val list = optList.getOrElse(List("localhost"))
I thought this should be straight forward:
import spire.math.Rational
val seq = Vector(Rational(1, 4), Rational(3, 4))
val sum = seq.sum // missing: scala.Numeric
val prod = seq.product // missing: scala.Numeric
I guess this is just a question of bringing the right stuff into implicit scope. But what do I import?
I can see that in order to get a RationalIsNumeric, I have to do something like this:
import spire.math.Numeric._
implicit val err = new ApproximationContext(Rational(1, 192))
implicit val num = RationalIsNumeric
But that just gives me a spire.math.Numeric. So I try with this additionally:
import spire.math.compat._
But no luck...
All that's needed is evidence of spire.math.compat.numeric[Rational]:
import spire.math._
val seq = Vector(Rational(1, 4), Rational(3, 4))
implicit val num = compat.numeric[Rational] // !
seq.sum // --> 1/1
seq.product // --> 3/16
It's also worth noting that Spire provides its own versions of sum and product that it calls qsum and qproduct:
import spire.implicits._
import spire.math._
Vector(Rational(1,3), Rational(1,2)).qsum // 5/6
Spire prefixes all its collection methods with q to avoid conflicting with Scala's built-in methods. Here's a (possibly incomplete) list:
qsum
qproduct
qnorm
qmin
qmax
qmean
qsorted
qsortedBy
qsortedWith
qselected
qshuffled
qsampled
qchoose
Sorry I came a bit late to this, I'm new to StackOverflow.