Unpacking Future[Option[MyType]] in Scala - scala

I am new to Scala and Play Framework so I am not quite sure what is wrong. I am trying to unpack a Future[Option[MyType]] given by a Slick DB controler (Play Framework). MyType is called BoundingBox in the code:
def getBoundingBoxByFileName(name: String) = {
val selectByName = boundingBoxTableQuery.filter{ boundingBoxTable =>
boundingBoxTable.name === name
}
db.run(selectByName.result.headOption)
}
BoundingBox type has a field called product_name. To retrieve this field I do the following:
val boundingBoxFutOpt = BoundingBoxQueryActions.getBoundingBoxByFileName("some_file")
val res = for {
optBb : Option[db.BoundingBox] <- boundingBoxFutOpt
} yield{
for(bb : db.BoundingBox <- optBb) yield {
println(s"${bb.product_name}")
}
}
This code does not yield anything on the output, though I have no compilation errors. If I change the println statement for some random text (not using the bb reference), it is also not printed on the console. To me it seems that the println statement is never executed.
I'll appreciate some directions on this problem.

It's likely that your program is terminating before the future has a chance to run the println. I think this will get you what you want:
import scala.concurrent.Await
import scala.concurrent.duration.Duration
// your code here
Await.result(res, Duration.Inf)
In your above example you're running a thread but then not giving it a chance to finish execution. The above will block until the future is complete.
It's worth nothing that you shouldn't use Await in production code as the blocking done negates the value of having code run in a separate thread.

Related

Is map of Future lazy or not?

Basically I mean:
for(v <- Future(long time operation)) yield v*someOtherValue
This expression returns another Future, but the question is, is the v*someOhterValue operation lazy or not? Will this expression block on getting the value of Future(long time operation)?
Or it is like a chain of callbacks?
A short experiment can test this question.
import concurrent._;
import concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
object TheFuture {
def main(args: Array[String]): Unit = {
val fut = for (v <- Future { Thread.sleep(2000) ; 10 }) yield v * 10;
println("For loop is finished...")
println(Await.ready(fut, Duration.Inf).value.get);
}
}
If we run this, we see For loop is finished... almost immediately, and then two seconds later, we see the result. So the act of performing map or similar operations on a future is not blocking.
A map (or, equivalently, your for comprehension) on a Future is not lazy: it will be executed as soon as possible on another thread. However, since it runs on another thread, it isn't blocking, either.
If you want to do the definition and execution of the Future separately, then you have to use something like a Monix Task.
https://monix.io/api/3.0/monix/eval/Task.html

Should a Scala process be marked scala.concurrent.blocking within a Scala Future?

I have created a Scala process, I read that this is blocking, should it be wrapped in a scala.concurrent.blocking? I'm confused, since the Process is going to call back to the log parameter here which would require this thread to do something I guess, so its not completely blocking?
import scala.sys.process.Process
import scala.concurrent.Future
import scala.sys.process.ProcessLogger
def something = Future {
val log = ProcessLogger(normal => {
lines = lines :+ normal
Logger.info("SFTPline added: " + normal)
},
error => {
Logger.info("SFTPERROR: " + error)
})
val success = scala.concurrent.blocking {
val result = Process(command).!(log)
lines.mkString("").contains("\"success\":true") && (result == 0)
}
}
Scala Process is actually get execute by the run function which return Process and exteciute it without blocking. the '!' is function that call the 'run' function and then call the exitValue() function of the Process. the 'exitValue()' Blocks until proccess exits)
calling Process(command).!(log) is actually same as run(log).exitValue() (well, not exactly but you can get the idea... see ProcessBuilderImpl.scala)
If you don't want to be blocked just call the run function instead.
Given that what you're returning is not a Future, your code must be blocking somewhere (I don't see how your example is "within a scala Future") - if you call a function that calls a callback, but then block waiting for that callback to be called, you're still blocking. So yes, declare it blocking.

Deal with Java NIO Iterator in Scala with Try

I recently learned how to use Scala's native Try type to handle errors. One good thing with Try is that I'm able to use for-comprehension and silently ignore the error.
However, this becomes a slight problem with Java's NIO package (which I really want to use).
val p = Paths.get("Some File Path")
for {
stream <- Try(Files.newDirectoryStream(p))
file:Path <- stream.iterator()
} yield file.getFileName
This would have been perfect. I intend to get all file names from a directory, and using a DirectoryStream[Path] is the best way because it scales really well. The NIO page says DirectoryStream has an iterator() method that returns an iterator. For Java's for loop, it's enough and can be used like this:
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path file: stream) {
System.out.println(file.getFileName());
}
}
However, Scala does not accept this. I was greeted with the error:
[error] /.../DAL.scala:42: value filter is not a member of java.util.Iterator[java.nio.file.Path]
[error] file:Path <- stream.iterator
I try to use JavaConverters, and it shows it handles Java Iterator type: scala.collection.Iterator <=> java.util.Iterator, but when I try to call it in this way: stream.iterator().asScala, the method is not reachable.
What should I do? How do I write nice Scala code while still using NIO package?
I don't actually quite get while in this for comprehension filter is being invoked, but note that stream.iterator() returns a Iterator[Path], not a Path, even though my IDE thinks it does, probably because he thinks he can apply map to it, but in truth this are methods which are not defined on java.util.Iterator[java.nio.file.Path] as the compiler confirms:
scala> for {
| stream <- Try(Files.newDirectoryStream(p))
| file <- stream.iterator()
| } yield file
<console>:13: error: value map is not a member of java.util.Iterator[java.nio.file.Path]
file <- stream.iterator()
This for comprehension translates to:
Try(Files.newDirectoryStream(p)).flatMap(stream => stream.iterator().map(...))
Where the second map is not defined. One solution could be found in this SO question, but I can't tell you how to use iterator in for comprehension here since in java iterator cannot be mapped on and I'm not sure you can convert it into the comprehension.
Edit:
I managed to find out more about the problem, I tried this for comprehension:
for {
stream <- Try(Files.newDirectoryStream(p))
file <- stream.iterator().toIterator
} yield file
This doesn't compile because:
found : Iterator[java.nio.file.Path]
required: scala.util.Try[?]
file <- stream.iterator().toIterator
It translates to:
Try(Files.newDirectoryStream(p)).flatMap(stream => stream.iterator().map(...))
But flatMap actually expects a Try back, in fact this works:
Try(Files.newDirectoryStream(p)).flatMap(stream => Try(stream.iterator().map(...)))
^
What I came up with:
import java.nio.file.{Paths, Files}
import util.Try
import scala.collection.JavaConversions._
Try(Files.newDirectoryStream(p))
.map(stream =>
stream
.iterator()
.toIterator
.toList
.map(path => path.getFileName.toString)
).getOrElse(List())
Which returns a List[String], unfortunately this is far from being as pretty as your for comprehension, maybe somebody else has a better idea.
I really like what Ende Neu wrote and it's hard to work with NIO in Scala. I want to preserve the efficiency brought from Java's Stream, so I decide to write this function instead. It still uses Try and I only need to deal with Success and Failure cases :)
It's not as smooth as I'd hope, and without Java 7's great try-with-resource feature, I have to close the stream by myself (which is terrible...), but this works out.
def readFileNames(filePath: String):Option[List[Path]] = {
val p = Paths.get(filePath)
val stream: Try[DirectoryStream[Path]] = Try(Files.newDirectoryStream(p))
val listOfFiles = List[Path]()
stream match {
case Success(st) =>
val iterator = st.iterator()
while (iterator.hasNext) {
listOfFiles :+ iterator.next()
}
case Failure(ex) => println(s"The file path is incorrect: ${ex.getMessage}")
}
stream.map(ds => ds.close())
if(listOfFiles.isEmpty) None else Some(listOfFiles)
}

Can't seem to get Future to run callback in Scala

(I've not included the imports so as not to clutter this question)
(This is the simplest possible Scala App (created using scala-minimal template on Typesafe Activator))
I'm trying to run a query against an Elasticsearch Server.
I've run the same code on sbt console and I can see the results alright.
However, when I run the following code, I see "END" (code after the callbacks) being printed, but neither the Success callback nor the Failure callback get run.
I'm a Scala noob, so maybe I'm doing something wrong here? This code compiles. (Just to let you know all the imports are there)
object Hello{
def main(args: Array[String]): Unit = {
val client = ElasticClient.remote("vm-3bsa", 9300)
val res:Future[SearchResponse] = client.execute{ search in "vulnerabilities/3bsa" query "css" }
res onComplete{
case Success(s) => println(s)
case Failure(t) => println("An error has occured: " + t)
}
println("END")
//EDIT start
Await.result(res,10.seconds)
//EDIT end
}
}
FINAL EDIT
Instead of using onComplete, it works if I, instead, print result of the call to Await.result:
val await=Await.result(res,10.seconds)
println(await)
// results shown
The main thread will register your onComplete, println("END") and then exit, this makes the program terminate so therefore you never see your onComplete callback.
You can use Await.result(future, timeout) to block the main thread to keep it alive until the answer arrives. In a server context that would be a big no-no but in a small app like this it is not a problem blocking one thread.

why does this scala by-name parameter behave weirdly

OK the question might not say much, but here's the deal:
I'm learning scala and decided to make an utility class "FuncThread" with a method which receives a by-name parameter function (I guess its called that because it's a function but without a parameter list) and then starts a thread with a runable which in turn executes the passed function, I wrote such a class as follows:
class FuncThread
{
def runInThread( func: => Unit)
{
val thread = new Thread(new Runnable()
{
def run()
{
func
}
}
thread.start()
}
}
Then I wrote a junit test as follows:
#Test
def weirdBehaivorTest()
{
var executed = false
val util = new FuncThread()
util.runInThread
{
executed = true
}
//the next line makes the test pass....
//val nonSense : () => Unit = () => { Console println "???" }
assertTrue(executed)
}
If I uncomment the second commented line, the test passes but if it remains commented the test fails, is this the correct behaviour? how and when do by-name parameter functions get executed?
I know Scala has the actors library but I wanted to try this since I've always wanted to do this in Java
Is this just a race condition? runInThread starts the thread but your assertion tests 'executed' before the other thread sets it to true. Adding your extra line means more code (and so time) is executed before the test, making it more likely that 'executed' has been set to true
It's also worth noting that (as of Scala 2.8), the construct you were trying to write is available in the standard library
import scala.actors.Futures._
future{
executed = true
}
This construct is actually more powerful than what you're describing, the thread calculation can return a value, and which can be waited for.
import scala.actors.Futures._
//forks off expensive calculation
val expensiveToCalculateNumber:Future[Int] = future{
bigExpensiveCalculation()
}
// do a lot of other stuff
//print out the result of the expensive calculation if it's ready, otherwise wait until it is
println( expensiveToCalculateNumber());